<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"><title>Spring高级45讲【第三章】：AOP | 狼族少年、血狼</title><meta name="author" content="狼族少年、血狼"><meta name="copyright" content="狼族少年、血狼"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="代理增强方式aspectj编译器增强先看一组例子： pom.xml文件中增加插件： 123456789101112131415161718192021222324&lt;plugin&gt;    &lt;groupId&gt;org.codehaus.mojo&lt;&#x2F;groupId&gt;    &lt;artifactId&gt;aspectj-maven-plugin&lt;&#x2F;artifa">
<meta property="og:type" content="article">
<meta property="og:title" content="Spring高级45讲【第三章】：AOP">
<meta property="og:url" content="https://geekwolfman.github.io/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%89%E7%AB%A0%E3%80%91%EF%BC%9AAOP.html">
<meta property="og:site_name" content="狼族少年、血狼">
<meta property="og:description" content="代理增强方式aspectj编译器增强先看一组例子： pom.xml文件中增加插件： 123456789101112131415161718192021222324&lt;plugin&gt;    &lt;groupId&gt;org.codehaus.mojo&lt;&#x2F;groupId&gt;    &lt;artifactId&gt;aspectj-maven-plugin&lt;&#x2F;artifa">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%89%E7%AB%A0%E3%80%91%EF%BC%9AAOP/01cover.jpg">
<meta property="article:published_time" content="2023-04-15T13:34:57.000Z">
<meta property="article:modified_time" content="2023-04-15T13:40:46.213Z">
<meta property="article:author" content="狼族少年、血狼">
<meta property="article:tag" content="spring">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%89%E7%AB%A0%E3%80%91%EF%BC%9AAOP/01cover.jpg"><link rel="shortcut icon" href="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/config/avatar/avatar.png"><link rel="canonical" href="https://geekwolfman.github.io/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%89%E7%AB%A0%E3%80%91%EF%BC%9AAOP.html"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.min.css" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: {"path":"/db.json","preload":false,"languages":{"hits_empty":"找不到您查询的内容：${query}"}},
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '天',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: undefined,
  source: {
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: false,
  isAnchor: false,
  percent: {
    toc: true,
    rightside: true,
  }
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: 'Spring高级45讲【第三章】：AOP',
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2023-04-15 21:40:46'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
    win.getCSS = (url,id = false) => new Promise((resolve, reject) => {
      const link = document.createElement('link')
      link.rel = 'stylesheet'
      link.href = url
      if (id) link.id = id
      link.onerror = reject
      link.onload = link.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        link.onload = link.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(link)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
    const detectApple = () => {
      if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
        document.documentElement.classList.add('apple')
      }
    }
    detectApple()
    })(window)</script><meta name="generator" content="Hexo 6.3.0"></head><body><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/pace-js/themes/blue/pace-theme-minimal.min.css"/><script src="https://cdn.jsdelivr.net/npm/pace-js/pace.min.js"></script><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/config/avatar/avatar.png" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">57</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">14</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">9</div></a></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/gallery/"><i class="fa-fw fas fa-images"></i><span> 画廊</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-paper-plane"></i><span> 关于</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url('https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%89%E7%AB%A0%E3%80%91%EF%BC%9AAOP/01cover.jpg')"><nav id="nav"><span id="blog-info"><a href="/" title="狼族少年、血狼"><span class="site-name">狼族少年、血狼</span></a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search" href="javascript:void(0);"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/gallery/"><i class="fa-fw fas fa-images"></i><span> 画廊</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-paper-plane"></i><span> 关于</span></a></div></div><div id="toggle-menu"><a class="site-page" href="javascript:void(0);"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">Spring高级45讲【第三章】：AOP</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2023-04-15T13:34:57.000Z" title="发表于 2023-04-15 21:34:57">2023-04-15</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2023-04-15T13:40:46.213Z" title="更新于 2023-04-15 21:40:46">2023-04-15</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/%E5%8E%9F%E7%90%86%E6%8E%A2%E7%A9%B6/">原理探究</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">12.4k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>62分钟</span></span><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title="Spring高级45讲【第三章】：AOP"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"><i class="fa-solid fa-spinner fa-spin"></i></span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><h1 id="代理增强方式"><a href="#代理增强方式" class="headerlink" title="代理增强方式"></a>代理增强方式</h1><h2 id="aspectj编译器增强"><a href="#aspectj编译器增强" class="headerlink" title="aspectj编译器增强"></a>aspectj编译器增强</h2><p>先看一组例子：</p>
<p><code>pom.xml</code>文件中增加插件：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.codehaus.mojo<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>aspectj-maven-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.14.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">complianceLevel</span>&gt;</span>1.8<span class="tag">&lt;/<span class="name">complianceLevel</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">source</span>&gt;</span>8<span class="tag">&lt;/<span class="name">source</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">target</span>&gt;</span>8<span class="tag">&lt;/<span class="name">target</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">showWeaveInfo</span>&gt;</span>true<span class="tag">&lt;/<span class="name">showWeaveInfo</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">verbose</span>&gt;</span>true<span class="tag">&lt;/<span class="name">verbose</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">Xlint</span>&gt;</span>ignore<span class="tag">&lt;/<span class="name">Xlint</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">encoding</span>&gt;</span>UTF-8<span class="tag">&lt;/<span class="name">encoding</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">executions</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">execution</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">goals</span>&gt;</span></span><br><span class="line">                <span class="comment">&lt;!-- use this goal to weave all your main classes --&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">goal</span>&gt;</span>compile<span class="tag">&lt;/<span class="name">goal</span>&gt;</span></span><br><span class="line">                <span class="comment">&lt;!-- use this goal to weave all your test classes --&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">goal</span>&gt;</span>test-compile<span class="tag">&lt;/<span class="name">goal</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">goals</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">execution</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">executions</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>编写<code>com.itheima.service.MyService</code>类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyService</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(MyService.class);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;foo()&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>编写<code>com.itheima.aop.MyAspect</code>类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">* ⬅️注意此切面并未被 Spring 管理</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="meta">@Aspect</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyAspect</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(MyAspect.class);</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Before(&quot;execution(* com.itheima.service.MyService.foo())&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;before()&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>MyAspect</code>类代理了<code>MyService</code>类，增加了前置通知。</p>
<p>编写启动类<code>com.itheima.A09</code>：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A09</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(A09.class);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="keyword">new</span> <span class="title class_">MyService</span>().foo();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">11:35:42.441 [main] DEBUG com.itheima.aop.MyAspect - before()</span><br><span class="line">11:35:42.444 [main] DEBUG com.itheima.service.MyService - foo()</span><br></pre></td></tr></table></figure>

<p><code>aspectj</code>编译器增强时在<strong>编译阶段直接修改类文件</strong>，并且不需要依赖<code>spring</code>容器，我们查看被改写的类文件：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyService</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(MyService.class);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">MyService</span><span class="params">()</span> &#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">        MyAspect.aspectOf().before();</span><br><span class="line">        log.debug(<span class="string">&quot;foo()&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>发现直接在目标方法前加上了我们的前置增强方法。</p>
<p>当<code>jdk</code>代理和<code>cglib</code>代理都不能使用时，可以考虑使用此方式实现代理。</p>
<h2 id="agent类加载增强"><a href="#agent类加载增强" class="headerlink" title="agent类加载增强"></a>agent类加载增强</h2><p>先看一组例子：</p>
<p>编写<code>com.itheima.service.MyService</code>类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyService</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(MyService.class);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">final</span> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;foo()&quot;</span>);</span><br><span class="line">        <span class="built_in">this</span>.bar();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">bar</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;bar()&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>编写<code>com.itheima.aop.MyAspect</code>类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">* ⬅️注意此切面并未被 Spring 管理</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="meta">@Aspect</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyAspect</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(MyAspect.class);</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Before(&quot;execution(* com.itheima.service.MyService.*())&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;before()&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>MyAspect</code>类代理了<code>MyService</code>类，并对所有方法增加了前置通知。</p>
<p>编写启动类<code>com.itheima.A10</code>：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">    注意几点</span></span><br><span class="line"><span class="comment">    1. 版本选择了 java 8, 因为目前的 aspectj-maven-plugin 1.14.0 最高只支持到 java 16</span></span><br><span class="line"><span class="comment">    2. 运行时需要在 VM options 里加入 -javaagent:C:/Users/manyh/.m2/repository/org/aspectj/aspectjweaver/1.9.7/aspectjweaver-1.9.7.jar</span></span><br><span class="line"><span class="comment">        把其中 C:/Users/manyh/.m2/repository 改为你自己 maven 仓库起始地址</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A10</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(A10.class);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">ConfigurableApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> SpringApplication.run(A10.class, args);</span><br><span class="line">        <span class="type">MyService</span> <span class="variable">service</span> <span class="operator">=</span> context.getBean(MyService.class);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// ⬇️MyService 并非代理, 但 foo 方法也被增强了, 做增强的 java agent, 在加载类时, 修改了 class 字节码</span></span><br><span class="line">        log.debug(<span class="string">&quot;service class: &#123;&#125;&quot;</span>, service.getClass());</span><br><span class="line">        service.foo();</span><br><span class="line"></span><br><span class="line">        context.close();</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>agent</code>类增强是在<strong>类加载阶段修改类文件</strong>进行的增强，运行时需要加上虚拟机参数：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">-javaagent:C:/Users/WolfMan/.m2/repository/org/aspectj/aspectjweaver/1.9.7/aspectjweaver-1.9.7.jar</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">2023-03-27 14:49:59.773 DEBUG 30220 --- [           main] com.itheima.aop.MyAspect                 : before()</span><br><span class="line">2023-03-27 14:49:59.773 DEBUG 30220 --- [           main] com.itheima.service.MyService            : foo()</span><br><span class="line">2023-03-27 14:49:59.773 DEBUG 30220 --- [           main] com.itheima.aop.MyAspect                 : before()</span><br><span class="line">2023-03-27 14:49:59.773 DEBUG 30220 --- [           main] com.itheima.service.MyService            : bar()</span><br></pre></td></tr></table></figure>

<p>这种代理方式突破了普通代理的限制，即在一个方法内调用另外的方法，这两个方法都被代理了，而普通的代理只能代理被调用的方法。</p>
<p>打开<code>arthas</code>，连接目标进程，使用<code>jad</code>命令反编译<code>MyService</code>类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.itheima.service;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.itheima.aop.MyAspect;</span><br><span class="line"><span class="keyword">import</span> org.slf4j.Logger;</span><br><span class="line"><span class="keyword">import</span> org.slf4j.LoggerFactory;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Service;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyService</span> &#123;</span><br><span class="line">   <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(MyService.class);</span><br><span class="line"></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">       MyAspect.aspectOf().before();</span><br><span class="line">       log.debug(<span class="string">&quot;foo()&quot;</span>);</span><br><span class="line">       <span class="built_in">this</span>.bar();</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">bar</span><span class="params">()</span> &#123;</span><br><span class="line">       MyAspect.aspectOf().before();</span><br><span class="line">       log.debug(<span class="string">&quot;bar()&quot;</span>);</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>发现在方法前插入了我们增强的方法。</p>
<h2 id="jdk代理增强"><a href="#jdk代理增强" class="headerlink" title="jdk代理增强"></a>jdk代理增强</h2><p>演示代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">JdkProxyDemo</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">interface</span> <span class="title class_">Foo</span> &#123;</span><br><span class="line">        <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">class</span> <span class="title class_">Target</span> <span class="keyword">implements</span> <span class="title class_">Foo</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;target foo&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// jdk 只能针对接口代理</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] param)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="comment">// 目标对象</span></span><br><span class="line">        <span class="type">Target</span> <span class="variable">target</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Target</span>();</span><br><span class="line">        <span class="comment">// 用来加载在运行期间动态生成的字节码</span></span><br><span class="line">        <span class="type">ClassLoader</span> <span class="variable">loader</span> <span class="operator">=</span> JdkProxyDemo.class.getClassLoader();</span><br><span class="line">        <span class="type">Foo</span> <span class="variable">proxy</span> <span class="operator">=</span> (Foo) Proxy.newProxyInstance(loader, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Foo.class&#125;, (p, method, args) -&gt; &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;before...&quot;</span>);</span><br><span class="line">            <span class="comment">// 目标.方法(参数)</span></span><br><span class="line">            <span class="comment">// 方法.invoke(目标, 参数);</span></span><br><span class="line">            <span class="type">Object</span> <span class="variable">result</span> <span class="operator">=</span> method.invoke(target, args);</span><br><span class="line">            System.out.println(<span class="string">&quot;after....&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> result; <span class="comment">// 让代理也返回目标方法执行的结果</span></span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        System.out.println(proxy.getClass());</span><br><span class="line"></span><br><span class="line">        proxy.foo();</span><br><span class="line"></span><br><span class="line">        System.in.read();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行<code>main()</code>方法，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">class com.itheima.a11.$Proxy0</span><br><span class="line">before...</span><br><span class="line">target foo</span><br><span class="line">after....</span><br></pre></td></tr></table></figure>

<p>发现对象被代理了，打印出我们真实调用的对象实际上是一个代理类对象。</p>
<p><code>invoke</code>方法的参数：</p>
<ul>
<li><code>Object</code>：代表代理类自身</li>
<li><code>Method</code>：代表代理类正在执行的方法</li>
<li><code>Object[]</code>：代表正在执行方法传入的参数</li>
</ul>
<p><code>jdk</code>代理的特点：</p>
<ul>
<li>被代理对象与代理对象为兄弟关系，都实现了父接口</li>
<li>被代理对象如果被final修饰没有影响</li>
</ul>
<h2 id="cglib代理增强"><a href="#cglib代理增强" class="headerlink" title="cglib代理增强"></a>cglib代理增强</h2><p>实例代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CglibProxyDemo</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Target</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;target foo&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 代理是子类型, 目标是父类型</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] param)</span> &#123;</span><br><span class="line">        <span class="type">Target</span> <span class="variable">target</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Target</span>();</span><br><span class="line"></span><br><span class="line">        <span class="type">Target</span> <span class="variable">proxy</span> <span class="operator">=</span> (Target) Enhancer.create(Target.class, (MethodInterceptor) (p, method, args, methodProxy) -&gt; &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;before...&quot;</span>);</span><br><span class="line">            <span class="type">Object</span> <span class="variable">result</span> <span class="operator">=</span> method.invoke(target, args); <span class="comment">// 用方法反射调用目标</span></span><br><span class="line">            System.out.println(<span class="string">&quot;after...&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> result;</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        proxy.foo();</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行<code>main()</code>方法，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">before...</span><br><span class="line">target foo</span><br><span class="line">after...</span><br></pre></td></tr></table></figure>

<p><code>MethodInterceptor</code>参数含义：</p>
<ul>
<li><code>Object</code>：代表代理类自身</li>
<li><code>Method</code>：代表代理类正在执行的方法</li>
<li><code>Object[]</code>：代表正在执行方法传入的参数</li>
<li><code>MethodProxy</code>：一个方法对象，提供更多功能</li>
</ul>
<p><code>cgilib</code>代理的特点：</p>
<ul>
<li>被代理对象与代理对象为父子关系，代理对象继承了被代理对象</li>
<li>被代理对象或者方法为final都不能使用cglib代理</li>
</ul>
<p><code>MethodInterceptor</code>参数中的<code>methodProxy</code>有两个方法可以避免反射调用：</p>
<ul>
<li><code>methodProxy.invoke(target, args)</code>：内部没有用反射, 需要目标(spring使用的这种方式)</li>
<li><code>methodProxy.invokeSuper(p, args)</code>：内部没有用反射, 需要代理</li>
</ul>
<p>实例使用：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Object</span> <span class="variable">result</span> <span class="operator">=</span> methodProxy.invoke(target, args); <span class="comment">// 内部没有用反射, 需要目标 （spring）</span></span><br><span class="line"><span class="type">Object</span> <span class="variable">result</span> <span class="operator">=</span> methodProxy.invokeSuper(p, args); <span class="comment">// 内部没有用反射, 需要代理</span></span><br></pre></td></tr></table></figure>

<h1 id="jdk动态代理原理"><a href="#jdk动态代理原理" class="headerlink" title="jdk动态代理原理"></a>jdk动态代理原理</h1><h2 id="模拟jdk动态代理"><a href="#模拟jdk动态代理" class="headerlink" title="模拟jdk动态代理"></a>模拟jdk动态代理</h2><p>代码演示：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 被代理对象实现的接口</span></span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">Foo</span> &#123;</span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">int</span> <span class="title function_">bar</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 自己实现的InvocationHandler接口</span></span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">InvocationHandler</span> &#123;</span><br><span class="line">    Object <span class="title function_">invoke</span><span class="params">(Object proxy, Method method, Object[] args)</span> <span class="keyword">throws</span> Throwable;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 被代理对象</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Target</span> <span class="keyword">implements</span> <span class="title class_">Foo</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;target foo&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">bar</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;target bar&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">100</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 代理类</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">$Proxy0</span> <span class="keyword">implements</span> <span class="title class_">Foo</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> Method foo;</span><br><span class="line">    <span class="keyword">static</span> Method bar;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            foo = Foo.class.getMethod(<span class="string">&quot;foo&quot;</span>);</span><br><span class="line">            bar = Foo.class.getMethod(<span class="string">&quot;bar&quot;</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (NoSuchMethodException e) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NoSuchMethodError</span>(e.getMessage());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    InvocationHandler h;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> $Proxy0(InvocationHandler h) &#123;</span><br><span class="line">        <span class="built_in">this</span>.h = h;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            h.invoke(<span class="built_in">this</span>, foo, <span class="keyword">new</span> <span class="title class_">Object</span>[<span class="number">0</span>]);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (RuntimeException | Error e) &#123;</span><br><span class="line">            <span class="keyword">throw</span> e;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Throwable e) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">UndeclaredThrowableException</span>(e);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">bar</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="type">Object</span> <span class="variable">result</span> <span class="operator">=</span> h.invoke(<span class="built_in">this</span>, bar, <span class="keyword">new</span> <span class="title class_">Object</span>[<span class="number">0</span>]);</span><br><span class="line">            <span class="keyword">return</span> (<span class="type">int</span>) result;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (RuntimeException | Error e) &#123;</span><br><span class="line">            <span class="keyword">throw</span> e;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Throwable e) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">UndeclaredThrowableException</span>(e);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用自己实现的代理类</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A12</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] param)</span> &#123;</span><br><span class="line">        <span class="type">Foo</span> <span class="variable">proxy</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">$Proxy0</span>(<span class="keyword">new</span> <span class="title class_">InvocationHandler</span>() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="keyword">public</span> Object <span class="title function_">invoke</span><span class="params">(Object proxy, Method method, Object[] args)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">                <span class="comment">// 1. 功能增强</span></span><br><span class="line">                System.out.println(<span class="string">&quot;before...&quot;</span>);</span><br><span class="line">                <span class="comment">// 2. 调用目标</span></span><br><span class="line">                <span class="keyword">return</span> method.invoke(<span class="keyword">new</span> <span class="title class_">Target</span>(), args);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        proxy.foo();</span><br><span class="line">        proxy.bar();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>模拟jdk动态代理思路：</p>
<ol>
<li>方法重写可以增强逻辑, 只不过这<strong>增强逻辑</strong>千变万化, 不能写死在代理内部</li>
<li>通过接口回调将<strong>增强逻辑</strong>置于代理类之外</li>
<li>配合接口方法反射(也是多态)，就可以再联动调用目标方法</li>
</ol>
<h2 id="jdk动态代理源码"><a href="#jdk动态代理源码" class="headerlink" title="jdk动态代理源码"></a>jdk动态代理源码</h2><p>打开arthas：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">C:/Path/jdk1.8.0_152/bin/java  -jar arthas-boot.jar</span><br></pre></td></tr></table></figure>

<p>连接进程，使用<code>jad</code>命令查看运行时的源码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.itheima.a11;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.itheima.a11.JdkProxyDemo;</span><br><span class="line"><span class="keyword">import</span> java.lang.invoke.MethodHandles;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.InvocationHandler;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Method;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Proxy;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.UndeclaredThrowableException;</span><br><span class="line"></span><br><span class="line"><span class="keyword">final</span> <span class="keyword">class</span> <span class="title class_">$Proxy0</span></span><br><span class="line"><span class="keyword">extends</span> <span class="title class_">Proxy</span></span><br><span class="line"><span class="keyword">implements</span> <span class="title class_">JdkProxyDemo</span>.Foo &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Method m0;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Method m1;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Method m2;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Method m3;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> $Proxy0(InvocationHandler invocationHandler) &#123;</span><br><span class="line">        <span class="built_in">super</span>(invocationHandler);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> &#123;</span><br><span class="line">        <span class="type">ClassLoader</span> <span class="variable">classLoader</span> <span class="operator">=</span> $Proxy0.class.getClassLoader();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            m0 = Class.forName(<span class="string">&quot;java.lang.Object&quot;</span>, <span class="literal">false</span>, classLoader).getMethod(<span class="string">&quot;hashCode&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[<span class="number">0</span>]);</span><br><span class="line">            m1 = Class.forName(<span class="string">&quot;java.lang.Object&quot;</span>, <span class="literal">false</span>, classLoader).getMethod(<span class="string">&quot;equals&quot;</span>, Class.forName(<span class="string">&quot;java.lang.Object&quot;</span>, <span class="literal">false</span>, classLoader));</span><br><span class="line">            m2 = Class.forName(<span class="string">&quot;java.lang.Object&quot;</span>, <span class="literal">false</span>, classLoader).getMethod(<span class="string">&quot;toString&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[<span class="number">0</span>]);</span><br><span class="line">            m3 = Class.forName(<span class="string">&quot;com.itheima.a11.JdkProxyDemo$Foo&quot;</span>, <span class="literal">false</span>, classLoader).getMethod(<span class="string">&quot;foo&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[<span class="number">0</span>]);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">catch</span> (NoSuchMethodException noSuchMethodException) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NoSuchMethodError</span>(noSuchMethodException.getMessage());</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">catch</span> (ClassNotFoundException classNotFoundException) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NoClassDefFoundError</span>(classNotFoundException.getMessage());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="type">boolean</span> <span class="title function_">equals</span><span class="params">(Object object)</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> (Boolean)<span class="built_in">this</span>.h.invoke(<span class="built_in">this</span>, m1, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;object&#125;);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">catch</span> (Error | RuntimeException throwable) &#123;</span><br><span class="line">            <span class="keyword">throw</span> throwable;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">catch</span> (Throwable throwable) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">UndeclaredThrowableException</span>(throwable);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> String <span class="title function_">toString</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> (String)<span class="built_in">this</span>.h.invoke(<span class="built_in">this</span>, m2, <span class="literal">null</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">catch</span> (Error | RuntimeException throwable) &#123;</span><br><span class="line">            <span class="keyword">throw</span> throwable;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">catch</span> (Throwable throwable) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">UndeclaredThrowableException</span>(throwable);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="type">int</span> <span class="title function_">hashCode</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> (Integer)<span class="built_in">this</span>.h.invoke(<span class="built_in">this</span>, m0, <span class="literal">null</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">catch</span> (Error | RuntimeException throwable) &#123;</span><br><span class="line">            <span class="keyword">throw</span> throwable;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">catch</span> (Throwable throwable) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">UndeclaredThrowableException</span>(throwable);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="built_in">this</span>.h.invoke(<span class="built_in">this</span>, m3, <span class="literal">null</span>);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">catch</span> (Error | RuntimeException throwable) &#123;</span><br><span class="line">            <span class="keyword">throw</span> throwable;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">catch</span> (Throwable throwable) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">UndeclaredThrowableException</span>(throwable);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> MethodHandles.Lookup <span class="title function_">proxyClassLookup</span><span class="params">(MethodHandles.Lookup lookup)</span> <span class="keyword">throws</span> IllegalAccessException &#123;</span><br><span class="line">        <span class="keyword">if</span> (lookup.lookupClass() == Proxy.class &amp;&amp; lookup.hasFullPrivilegeAccess()) &#123;</span><br><span class="line">            <span class="keyword">return</span> MethodHandles.lookup();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalAccessException</span>(lookup.toString());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>jdk直接生成字节码使用的技术是ASM，接下来演示ASM生成的字节码。</p>
<p>在idea中安装<code>ASM Bytecode Viewer Support Kotlin</code>插件，编写以下代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 代理接口</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Foo</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 代理类</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">$Proxy0</span> <span class="keyword">extends</span> <span class="title class_">Proxy</span> <span class="keyword">implements</span> <span class="title class_">Foo</span> &#123;</span><br><span class="line">    <span class="keyword">static</span> Method foo;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> $Proxy0(InvocationHandler h) &#123;</span><br><span class="line">        <span class="built_in">super</span>(h);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="built_in">this</span>.h.invoke(<span class="built_in">this</span>, foo, <span class="literal">null</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Throwable var2) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">UndeclaredThrowableException</span>(var2);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            foo = Foo.class.getMethod(<span class="string">&quot;foo&quot;</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (NoSuchMethodException var1) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NoSuchMethodError</span>(var1.getMessage());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>编译这两个类，在<code>$Proxy0</code>中右键<code>ASM Bytecode Viewer</code>，选择<code>ASMified</code>选项：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> asm.com.itheima;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.objectweb.asm.AnnotationVisitor;</span><br><span class="line"><span class="keyword">import</span> org.objectweb.asm.Attribute;</span><br><span class="line"><span class="keyword">import</span> org.objectweb.asm.ClassReader;</span><br><span class="line"><span class="keyword">import</span> org.objectweb.asm.ClassWriter;</span><br><span class="line"><span class="keyword">import</span> org.objectweb.asm.ConstantDynamic;</span><br><span class="line"><span class="keyword">import</span> org.objectweb.asm.FieldVisitor;</span><br><span class="line"><span class="keyword">import</span> org.objectweb.asm.Handle;</span><br><span class="line"><span class="keyword">import</span> org.objectweb.asm.Label;</span><br><span class="line"><span class="keyword">import</span> org.objectweb.asm.MethodVisitor;</span><br><span class="line"><span class="keyword">import</span> org.objectweb.asm.Opcodes;</span><br><span class="line"><span class="keyword">import</span> org.objectweb.asm.Type;</span><br><span class="line"><span class="keyword">import</span> org.objectweb.asm.TypePath;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">$Proxy0Dump</span> <span class="keyword">implements</span> <span class="title class_">Opcodes</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">byte</span>[] dump() <span class="keyword">throws</span> Exception &#123;</span><br><span class="line"></span><br><span class="line">        <span class="type">ClassWriter</span> <span class="variable">classWriter</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ClassWriter</span>(<span class="number">0</span>);</span><br><span class="line">        FieldVisitor fieldVisitor;</span><br><span class="line">        MethodVisitor methodVisitor;</span><br><span class="line">        AnnotationVisitor annotationVisitor0;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 定义类</span></span><br><span class="line">        classWriter.visit(V1_8, ACC_PUBLIC | ACC_SUPER, <span class="string">&quot;com/itheima/$Proxy0&quot;</span>, <span class="literal">null</span>, <span class="string">&quot;java/lang/reflect/Proxy&quot;</span>, <span class="keyword">new</span> <span class="title class_">String</span>[]&#123;<span class="string">&quot;com/itheima/Foo&quot;</span>&#125;);</span><br><span class="line"></span><br><span class="line">        &#123;</span><br><span class="line">            <span class="comment">// 定义静态成员变量</span></span><br><span class="line">            fieldVisitor = classWriter.visitField(ACC_STATIC, <span class="string">&quot;foo&quot;</span>, <span class="string">&quot;Ljava/lang/reflect/Method;&quot;</span>, <span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line">            fieldVisitor.visitEnd();</span><br><span class="line">        &#125;</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="comment">// 定义构造方法</span></span><br><span class="line">            methodVisitor = classWriter.visitMethod(ACC_PUBLIC, <span class="string">&quot;&lt;init&gt;&quot;</span>, <span class="string">&quot;(Ljava/lang/reflect/InvocationHandler;)V&quot;</span>, <span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line">            <span class="comment">// 定义方法内的字节码</span></span><br><span class="line">            methodVisitor.visitCode();</span><br><span class="line">            methodVisitor.visitVarInsn(ALOAD, <span class="number">0</span>);</span><br><span class="line">            methodVisitor.visitVarInsn(ALOAD, <span class="number">1</span>);</span><br><span class="line">            methodVisitor.visitMethodInsn(INVOKESPECIAL, <span class="string">&quot;java/lang/reflect/Proxy&quot;</span>, <span class="string">&quot;&lt;init&gt;&quot;</span>, <span class="string">&quot;(Ljava/lang/reflect/InvocationHandler;)V&quot;</span>, <span class="literal">false</span>);</span><br><span class="line">            methodVisitor.visitInsn(RETURN);</span><br><span class="line">            methodVisitor.visitMaxs(<span class="number">2</span>, <span class="number">2</span>);</span><br><span class="line">            methodVisitor.visitEnd();</span><br><span class="line">        &#125;</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="comment">// 定义方法</span></span><br><span class="line">            methodVisitor = classWriter.visitMethod(ACC_PUBLIC, <span class="string">&quot;foo&quot;</span>, <span class="string">&quot;()V&quot;</span>, <span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line">            methodVisitor.visitCode();</span><br><span class="line">            <span class="type">Label</span> <span class="variable">label0</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Label</span>();</span><br><span class="line">            <span class="type">Label</span> <span class="variable">label1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Label</span>();</span><br><span class="line">            <span class="type">Label</span> <span class="variable">label2</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Label</span>();</span><br><span class="line">            methodVisitor.visitTryCatchBlock(label0, label1, label2, <span class="string">&quot;java/lang/Throwable&quot;</span>);</span><br><span class="line">            methodVisitor.visitLabel(label0);</span><br><span class="line">            methodVisitor.visitVarInsn(ALOAD, <span class="number">0</span>);</span><br><span class="line">            methodVisitor.visitFieldInsn(GETFIELD, <span class="string">&quot;com/itheima/$Proxy0&quot;</span>, <span class="string">&quot;h&quot;</span>, <span class="string">&quot;Ljava/lang/reflect/InvocationHandler;&quot;</span>);</span><br><span class="line">            methodVisitor.visitVarInsn(ALOAD, <span class="number">0</span>);</span><br><span class="line">            methodVisitor.visitFieldInsn(GETSTATIC, <span class="string">&quot;com/itheima/$Proxy0&quot;</span>, <span class="string">&quot;foo&quot;</span>, <span class="string">&quot;Ljava/lang/reflect/Method;&quot;</span>);</span><br><span class="line">            methodVisitor.visitInsn(ACONST_NULL);</span><br><span class="line">            methodVisitor.visitMethodInsn(INVOKEINTERFACE, <span class="string">&quot;java/lang/reflect/InvocationHandler&quot;</span>, <span class="string">&quot;invoke&quot;</span>, <span class="string">&quot;(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;&quot;</span>, <span class="literal">true</span>);</span><br><span class="line">            methodVisitor.visitInsn(POP);</span><br><span class="line">            methodVisitor.visitLabel(label1);</span><br><span class="line">            <span class="type">Label</span> <span class="variable">label3</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Label</span>();</span><br><span class="line">            methodVisitor.visitJumpInsn(GOTO, label3);</span><br><span class="line">            methodVisitor.visitLabel(label2);</span><br><span class="line">            methodVisitor.visitVarInsn(ASTORE, <span class="number">1</span>);</span><br><span class="line">            methodVisitor.visitTypeInsn(NEW, <span class="string">&quot;java/lang/reflect/UndeclaredThrowableException&quot;</span>);</span><br><span class="line">            methodVisitor.visitInsn(DUP);</span><br><span class="line">            methodVisitor.visitVarInsn(ALOAD, <span class="number">1</span>);</span><br><span class="line">            methodVisitor.visitMethodInsn(INVOKESPECIAL, <span class="string">&quot;java/lang/reflect/UndeclaredThrowableException&quot;</span>, <span class="string">&quot;&lt;init&gt;&quot;</span>, <span class="string">&quot;(Ljava/lang/Throwable;)V&quot;</span>, <span class="literal">false</span>);</span><br><span class="line">            methodVisitor.visitInsn(ATHROW);</span><br><span class="line">            methodVisitor.visitLabel(label3);</span><br><span class="line">            methodVisitor.visitInsn(RETURN);</span><br><span class="line">            methodVisitor.visitMaxs(<span class="number">4</span>, <span class="number">2</span>);</span><br><span class="line">            methodVisitor.visitEnd();</span><br><span class="line">        &#125;</span><br><span class="line">        &#123;</span><br><span class="line">            methodVisitor = classWriter.visitMethod(ACC_STATIC, <span class="string">&quot;&lt;clinit&gt;&quot;</span>, <span class="string">&quot;()V&quot;</span>, <span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line">            methodVisitor.visitCode();</span><br><span class="line">            <span class="type">Label</span> <span class="variable">label0</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Label</span>();</span><br><span class="line">            <span class="type">Label</span> <span class="variable">label1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Label</span>();</span><br><span class="line">            <span class="type">Label</span> <span class="variable">label2</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Label</span>();</span><br><span class="line">            methodVisitor.visitTryCatchBlock(label0, label1, label2, <span class="string">&quot;java/lang/NoSuchMethodException&quot;</span>);</span><br><span class="line">            methodVisitor.visitLabel(label0);</span><br><span class="line">            methodVisitor.visitLdcInsn(Type.getType(<span class="string">&quot;Lcom/itheima/Foo;&quot;</span>));</span><br><span class="line">            methodVisitor.visitLdcInsn(<span class="string">&quot;foo&quot;</span>);</span><br><span class="line">            methodVisitor.visitInsn(ICONST_0);</span><br><span class="line">            methodVisitor.visitTypeInsn(ANEWARRAY, <span class="string">&quot;java/lang/Class&quot;</span>);</span><br><span class="line">            methodVisitor.visitMethodInsn(INVOKEVIRTUAL, <span class="string">&quot;java/lang/Class&quot;</span>, <span class="string">&quot;getMethod&quot;</span>, <span class="string">&quot;(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;&quot;</span>, <span class="literal">false</span>);</span><br><span class="line">            methodVisitor.visitFieldInsn(PUTSTATIC, <span class="string">&quot;com/itheima/$Proxy0&quot;</span>, <span class="string">&quot;foo&quot;</span>, <span class="string">&quot;Ljava/lang/reflect/Method;&quot;</span>);</span><br><span class="line">            methodVisitor.visitLabel(label1);</span><br><span class="line">            <span class="type">Label</span> <span class="variable">label3</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Label</span>();</span><br><span class="line">            methodVisitor.visitJumpInsn(GOTO, label3);</span><br><span class="line">            methodVisitor.visitLabel(label2);</span><br><span class="line">            methodVisitor.visitVarInsn(ASTORE, <span class="number">0</span>);</span><br><span class="line">            methodVisitor.visitTypeInsn(NEW, <span class="string">&quot;java/lang/NoSuchMethodError&quot;</span>);</span><br><span class="line">            methodVisitor.visitInsn(DUP);</span><br><span class="line">            methodVisitor.visitVarInsn(ALOAD, <span class="number">0</span>);</span><br><span class="line">            methodVisitor.visitMethodInsn(INVOKEVIRTUAL, <span class="string">&quot;java/lang/NoSuchMethodException&quot;</span>, <span class="string">&quot;getMessage&quot;</span>, <span class="string">&quot;()Ljava/lang/String;&quot;</span>, <span class="literal">false</span>);</span><br><span class="line">            methodVisitor.visitMethodInsn(INVOKESPECIAL, <span class="string">&quot;java/lang/NoSuchMethodError&quot;</span>, <span class="string">&quot;&lt;init&gt;&quot;</span>, <span class="string">&quot;(Ljava/lang/String;)V&quot;</span>, <span class="literal">false</span>);</span><br><span class="line">            methodVisitor.visitInsn(ATHROW);</span><br><span class="line">            methodVisitor.visitLabel(label3);</span><br><span class="line">            methodVisitor.visitInsn(RETURN);</span><br><span class="line">            methodVisitor.visitMaxs(<span class="number">3</span>, <span class="number">1</span>);</span><br><span class="line">            methodVisitor.visitEnd();</span><br><span class="line">        &#125;</span><br><span class="line">        classWriter.visitEnd();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 生成字节数组</span></span><br><span class="line">        <span class="keyword">return</span> classWriter.toByteArray();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>我们可以使用此类生成代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestProxy</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">byte</span>[] dump = $Proxy0Dump.dump();</span><br><span class="line"></span><br><span class="line">        <span class="type">FileOutputStream</span> <span class="variable">os</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;$Proxy0.class&quot;</span>);</span><br><span class="line">        os.write(dump, <span class="number">0</span>, dump.length);</span><br><span class="line">        os.close();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在项目目录下生成文件<code>$Proxy0.class</code>：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.itheima;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.InvocationHandler;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Method;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Proxy;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.UndeclaredThrowableException;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">$Proxy0</span> <span class="keyword">extends</span> <span class="title class_">Proxy</span> <span class="keyword">implements</span> <span class="title class_">Foo</span> &#123;</span><br><span class="line">    <span class="keyword">static</span> Method foo;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> $Proxy0(InvocationHandler h) &#123;</span><br><span class="line">        <span class="built_in">super</span>(h);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="built_in">this</span>.h.invoke(<span class="built_in">this</span>, foo, (Object[])<span class="literal">null</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Throwable var2) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">UndeclaredThrowableException</span>(var2);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            foo = Foo.class.getMethod(<span class="string">&quot;foo&quot;</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (NoSuchMethodException var1) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NoSuchMethodError</span>(var1.getMessage());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>我们也可以使用<code>$Proxy0Dump</code>类调用方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestProxy</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">byte</span>[] dump = $Proxy0Dump.dump();</span><br><span class="line">        <span class="type">ClassLoader</span> <span class="variable">loader</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ClassLoader</span>() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="keyword">protected</span> Class&lt;?&gt; findClass(String name) <span class="keyword">throws</span> ClassNotFoundException &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="built_in">super</span>.defineClass(name, dump, <span class="number">0</span>, dump.length);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        Class&lt;?&gt; proxyClass = loader.loadClass(<span class="string">&quot;com.itheima.$Proxy0&quot;</span>);</span><br><span class="line"></span><br><span class="line">        Constructor&lt;?&gt; constructor = proxyClass.getConstructor(InvocationHandler.class);</span><br><span class="line">        <span class="type">Foo</span> <span class="variable">proxy</span> <span class="operator">=</span> (Foo) constructor.newInstance(<span class="keyword">new</span> <span class="title class_">InvocationHandler</span>() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="keyword">public</span> Object <span class="title function_">invoke</span><span class="params">(Object proxy, Method method, Object[] args)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">                System.out.println(<span class="string">&quot;before...&quot;</span>);</span><br><span class="line">                System.out.println(<span class="string">&quot;调用目标&quot;</span>);</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        proxy.foo();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行main()方法，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">before...</span><br><span class="line">调用目标</span><br></pre></td></tr></table></figure>

<h2 id="jdk反射优化"><a href="#jdk反射优化" class="headerlink" title="jdk反射优化"></a>jdk反射优化</h2><p>编写测试类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.lang.reflect.Field;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Method;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 运行时请添加 --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/jdk.internal.reflect=ALL-UNNAMED</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestMethodInvoke</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">Method</span> <span class="variable">foo</span> <span class="operator">=</span> TestMethodInvoke.class.getMethod(<span class="string">&quot;foo&quot;</span>, <span class="type">int</span>.class);</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">1</span>; i &lt;= <span class="number">17</span>; i++) &#123;</span><br><span class="line">            show(i, foo);</span><br><span class="line">            foo.invoke(<span class="literal">null</span>, i);</span><br><span class="line">        &#125;</span><br><span class="line">        System.in.read();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 方法反射调用时, 底层 MethodAccessor 的实现类</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">show</span><span class="params">(<span class="type">int</span> i, Method foo)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">Method</span> <span class="variable">getMethodAccessor</span> <span class="operator">=</span> Method.class.getDeclaredMethod(<span class="string">&quot;getMethodAccessor&quot;</span>);</span><br><span class="line">        getMethodAccessor.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        <span class="type">Object</span> <span class="variable">invoke</span> <span class="operator">=</span> getMethodAccessor.invoke(foo);</span><br><span class="line">        <span class="keyword">if</span> (invoke == <span class="literal">null</span>) &#123;</span><br><span class="line">            System.out.println(i + <span class="string">&quot;:&quot;</span> + <span class="literal">null</span>);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">Field</span> <span class="variable">delegate</span> <span class="operator">=</span> Class.forName(<span class="string">&quot;jdk.internal.reflect.DelegatingMethodAccessorImpl&quot;</span>).getDeclaredField(<span class="string">&quot;delegate&quot;</span>);</span><br><span class="line">        delegate.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        System.out.println(i + <span class="string">&quot;:&quot;</span> + delegate.get(invoke));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">(<span class="type">int</span> i)</span> &#123;</span><br><span class="line">        System.out.println(i + <span class="string">&quot;:&quot;</span> + <span class="string">&quot;foo&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台输出：</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1</span>:<span class="keyword">null</span></span><br><span class="line"><span class="number">1</span>:foo</span><br><span class="line"><span class="number">2</span>:jdk.internal.reflect.NativeMethodAccessorImpl<span class="variable">@5b37e0d2</span></span><br><span class="line"><span class="number">2</span>:foo</span><br><span class="line"><span class="number">3</span>:jdk.internal.reflect.NativeMethodAccessorImpl<span class="variable">@5b37e0d2</span></span><br><span class="line"><span class="number">3</span>:foo</span><br><span class="line"><span class="number">4</span>:jdk.internal.reflect.NativeMethodAccessorImpl<span class="variable">@5b37e0d2</span></span><br><span class="line"><span class="number">4</span>:foo</span><br><span class="line"><span class="number">5</span>:jdk.internal.reflect.NativeMethodAccessorImpl<span class="variable">@5b37e0d2</span></span><br><span class="line"><span class="number">5</span>:foo</span><br><span class="line"><span class="number">6</span>:jdk.internal.reflect.NativeMethodAccessorImpl<span class="variable">@5b37e0d2</span></span><br><span class="line"><span class="number">6</span>:foo</span><br><span class="line"><span class="number">7</span>:jdk.internal.reflect.NativeMethodAccessorImpl<span class="variable">@5b37e0d2</span></span><br><span class="line"><span class="number">7</span>:foo</span><br><span class="line"><span class="number">8</span>:jdk.internal.reflect.NativeMethodAccessorImpl<span class="variable">@5b37e0d2</span></span><br><span class="line"><span class="number">8</span>:foo</span><br><span class="line"><span class="number">9</span>:jdk.internal.reflect.NativeMethodAccessorImpl<span class="variable">@5b37e0d2</span></span><br><span class="line"><span class="number">9</span>:foo</span><br><span class="line"><span class="number">10</span>:jdk.internal.reflect.NativeMethodAccessorImpl<span class="variable">@5b37e0d2</span></span><br><span class="line"><span class="number">10</span>:foo</span><br><span class="line"><span class="number">11</span>:jdk.internal.reflect.NativeMethodAccessorImpl<span class="variable">@5b37e0d2</span></span><br><span class="line"><span class="number">11</span>:foo</span><br><span class="line"><span class="number">12</span>:jdk.internal.reflect.NativeMethodAccessorImpl<span class="variable">@5b37e0d2</span></span><br><span class="line"><span class="number">12</span>:foo</span><br><span class="line"><span class="number">13</span>:jdk.internal.reflect.NativeMethodAccessorImpl<span class="variable">@5b37e0d2</span></span><br><span class="line"><span class="number">13</span>:foo</span><br><span class="line"><span class="number">14</span>:jdk.internal.reflect.NativeMethodAccessorImpl<span class="variable">@5b37e0d2</span></span><br><span class="line"><span class="number">14</span>:foo</span><br><span class="line"><span class="number">15</span>:jdk.internal.reflect.NativeMethodAccessorImpl<span class="variable">@5b37e0d2</span></span><br><span class="line"><span class="number">15</span>:foo</span><br><span class="line"><span class="number">16</span>:jdk.internal.reflect.NativeMethodAccessorImpl<span class="variable">@5b37e0d2</span></span><br><span class="line"><span class="number">16</span>:foo</span><br><span class="line"><span class="number">17</span>:jdk.internal.reflect.GeneratedMethodAccessor2<span class="variable">@2d38eb89</span></span><br><span class="line"><span class="number">17</span>:foo</span><br></pre></td></tr></table></figure>

<p>我们发现前面16次调用都是使用<code>jdk.internal.reflect.NativeMethodAccessorImpl@5b37e0d2</code>，这个实现是使用java本地api实现的，性能比较低。</p>
<p>我们可以使用arthas查看<code>jdk.internal.reflect.GeneratedMethodAccessor2</code>的实现：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> jdk.internal.reflect;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.itheima.a12.TestMethodInvoke;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.InvocationTargetException;</span><br><span class="line"><span class="keyword">import</span> jdk.internal.reflect.MethodAccessorImpl;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">GeneratedMethodAccessor2</span></span><br><span class="line"><span class="keyword">extends</span> <span class="title class_">MethodAccessorImpl</span> &#123;</span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">     * Loose catch block</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">invoke</span><span class="params">(Object object, Object[] objectArray)</span> <span class="keyword">throws</span> InvocationTargetException &#123;</span><br><span class="line">        <span class="type">char</span> c;</span><br><span class="line">        block9: &#123;</span><br><span class="line">            <span class="keyword">if</span> (objectArray.length != <span class="number">1</span>) &#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="type">Object</span> <span class="variable">object2</span> <span class="operator">=</span> objectArray[<span class="number">0</span>];</span><br><span class="line">            <span class="keyword">if</span> (object2 <span class="keyword">instanceof</span> Byte) &#123;</span><br><span class="line">                c = ((Byte)object2).byteValue();</span><br><span class="line">                <span class="keyword">break</span> block9;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (object2 <span class="keyword">instanceof</span> Character) &#123;</span><br><span class="line">                c = ((Character)object2).charValue();</span><br><span class="line">                <span class="keyword">break</span> block9;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (object2 <span class="keyword">instanceof</span> Short) &#123;</span><br><span class="line">                c = (<span class="type">char</span>)((Short)object2).shortValue();</span><br><span class="line">                <span class="keyword">break</span> block9;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (object2 <span class="keyword">instanceof</span> Integer) &#123;</span><br><span class="line">                c = (<span class="type">char</span>)((Integer)object2).intValue();</span><br><span class="line">                <span class="keyword">break</span> block9;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">// 直接调用，没有使用反射调用</span></span><br><span class="line">            TestMethodInvoke.foo((<span class="type">int</span>)c);</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">catch</span> (Throwable throwable) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">InvocationTargetException</span>(throwable);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">catch</span> (ClassCastException | NullPointerException runtimeException) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>(<span class="built_in">super</span>.toString());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>我们发现jdk在运行时直接生成了<code>jdk.internal.reflect.GeneratedMethodAccessor2</code>类，然后直接调用其方法，避免了反射调用的性能损耗。缺点是每个方法都需要生成一个代理类，而cglib是一个类所有方法的代理生成两个代理类进行直接调用。</p>
<h1 id="cglib动态代理原理"><a href="#cglib动态代理原理" class="headerlink" title="cglib动态代理原理"></a>cglib动态代理原理</h1><h2 id="模拟cglib动态代理"><a href="#模拟cglib动态代理" class="headerlink" title="模拟cglib动态代理"></a>模拟cglib动态代理</h2><p>代码演示：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 代理目标类</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Target</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;save()&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">(<span class="type">int</span> i)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;save(int)&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">(<span class="type">long</span> j)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;save(long)&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//代理类</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Proxy</span> <span class="keyword">extends</span> <span class="title class_">Target</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> MethodInterceptor methodInterceptor;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setMethodInterceptor</span><span class="params">(MethodInterceptor methodInterceptor)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.methodInterceptor = methodInterceptor;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> Method save0;</span><br><span class="line">    <span class="keyword">static</span> Method save1;</span><br><span class="line">    <span class="keyword">static</span> Method save2;</span><br><span class="line">    <span class="keyword">static</span> MethodProxy save0Proxy;</span><br><span class="line">    <span class="keyword">static</span> MethodProxy save1Proxy;</span><br><span class="line">    <span class="keyword">static</span> MethodProxy save2Proxy;</span><br><span class="line">    <span class="keyword">static</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            save0 = Target.class.getMethod(<span class="string">&quot;save&quot;</span>);</span><br><span class="line">            save1 = Target.class.getMethod(<span class="string">&quot;save&quot;</span>, <span class="type">int</span>.class);</span><br><span class="line">            save2 = Target.class.getMethod(<span class="string">&quot;save&quot;</span>, <span class="type">long</span>.class);</span><br><span class="line">            <span class="comment">//&quot;()V&quot; 代表参数为空，返回值为void， &quot;(I)V&quot;代表参数为int类型，返回值为空</span></span><br><span class="line">            save0Proxy = MethodProxy.create(Target.class, Proxy.class, <span class="string">&quot;()V&quot;</span>, <span class="string">&quot;save&quot;</span>, <span class="string">&quot;saveSuper&quot;</span>);</span><br><span class="line">            save1Proxy = MethodProxy.create(Target.class, Proxy.class, <span class="string">&quot;(I)V&quot;</span>, <span class="string">&quot;save&quot;</span>, <span class="string">&quot;saveSuper&quot;</span>);</span><br><span class="line">            save2Proxy = MethodProxy.create(Target.class, Proxy.class, <span class="string">&quot;(J)V&quot;</span>, <span class="string">&quot;save&quot;</span>, <span class="string">&quot;saveSuper&quot;</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (NoSuchMethodException e) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NoSuchMethodError</span>(e.getMessage());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; 带原始功能的方法</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">saveSuper</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>.save();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">saveSuper</span><span class="params">(<span class="type">int</span> i)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>.save(i);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">saveSuper</span><span class="params">(<span class="type">long</span> j)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>.save(j);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; 带增强功能的方法</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            methodInterceptor.intercept(<span class="built_in">this</span>, save0, <span class="keyword">new</span> <span class="title class_">Object</span>[<span class="number">0</span>], save0Proxy);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Throwable e) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">UndeclaredThrowableException</span>(e);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">(<span class="type">int</span> i)</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            methodInterceptor.intercept(<span class="built_in">this</span>, save1, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;i&#125;, save1Proxy);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Throwable e) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">UndeclaredThrowableException</span>(e);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">(<span class="type">long</span> j)</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            methodInterceptor.intercept(<span class="built_in">this</span>, save2, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;j&#125;, save2Proxy);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Throwable e) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">UndeclaredThrowableException</span>(e);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 启动类</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A13</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">Proxy</span> <span class="variable">proxy</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Proxy</span>();</span><br><span class="line">        <span class="type">Target</span> <span class="variable">target</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Target</span>();</span><br><span class="line">        proxy.setMethodInterceptor(<span class="keyword">new</span> <span class="title class_">MethodInterceptor</span>() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="keyword">public</span> Object <span class="title function_">intercept</span><span class="params">(Object p, Method method, Object[] args,</span></span><br><span class="line"><span class="params">                                    MethodProxy methodProxy)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">                System.out.println(<span class="string">&quot;before...&quot;</span>);</span><br><span class="line">                <span class="keyword">return</span> method.invoke(target, args); <span class="comment">// 反射调用</span></span><br><span class="line">                <span class="comment">// FastClass</span></span><br><span class="line"><span class="comment">//                return methodProxy.invoke(target, args); // 内部无反射, 结合目标用</span></span><br><span class="line"><span class="comment">//                return methodProxy.invokeSuper(p, args); // 内部无反射, 结合代理用</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        proxy.save();</span><br><span class="line">        proxy.save(<span class="number">1</span>);</span><br><span class="line">        proxy.save(<span class="number">2L</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">before...</span><br><span class="line">save()</span><br><span class="line">before...</span><br><span class="line">save(int)</span><br><span class="line">before...</span><br><span class="line">save(long)</span><br></pre></td></tr></table></figure>

<h2 id="MethodProxy原理"><a href="#MethodProxy原理" class="headerlink" title="MethodProxy原理"></a>MethodProxy原理</h2><p><code>methodProxy</code>的<code>invoke()</code>方法和<code>invokeSuper()</code>方法都可以避免反射调用，以提高动态代理的性能，接下来我们介绍这两种方法。</p>
<h3 id="invoke"><a href="#invoke" class="headerlink" title="invoke()"></a><strong>invoke()</strong></h3><p>cglib在调用<code>invoke()</code>方法和<code>invokeSuper()</code>方法的时候会生成两个代理类，这两个代理类都继承了<code>org.springframework.cglib.reflect.FastClass</code>，这两个代理类中的一些关键方法就避免了反射。</p>
<p>其中有两个关键抽象方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="type">int</span> <span class="title function_">getIndex</span><span class="params">(Signature var1)</span>;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> Object <span class="title function_">invoke</span><span class="params">(<span class="type">int</span> var1, Object var2, Object[] var3)</span> <span class="keyword">throws</span> InvocationTargetException;</span><br></pre></td></tr></table></figure>

<p>接下来模拟<code>method.invoke()</code>方法的实现，取名叫<code>TargetFastClass</code>，主要实现以上两个抽象方法的功能，<code>TargetFastClass</code>会在<code>Proxy</code>调用<code>MethodProxy.create()</code>的时候创建：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TargetFastClass</span> &#123;</span><br><span class="line">    <span class="keyword">static</span> <span class="type">Signature</span> <span class="variable">s0</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Signature</span>(<span class="string">&quot;save&quot;</span>, <span class="string">&quot;()V&quot;</span>);</span><br><span class="line">    <span class="keyword">static</span> <span class="type">Signature</span> <span class="variable">s1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Signature</span>(<span class="string">&quot;save&quot;</span>, <span class="string">&quot;(I)V&quot;</span>);</span><br><span class="line">    <span class="keyword">static</span> <span class="type">Signature</span> <span class="variable">s2</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Signature</span>(<span class="string">&quot;save&quot;</span>, <span class="string">&quot;(J)V&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 根据方法信息获取目标方法的编号</span></span><br><span class="line"><span class="comment">     * Target</span></span><br><span class="line"><span class="comment">     *             save()              0</span></span><br><span class="line"><span class="comment">     *             save(int)           1</span></span><br><span class="line"><span class="comment">     *             save(long)          2</span></span><br><span class="line"><span class="comment">     * signature 包括方法名字、参数返回值</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> signature</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">getIndex</span><span class="params">(Signature signature)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (s0.equals(signature)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (s1.equals(signature)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (s2.equals(signature)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="number">2</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 根据方法编号, 正常调用目标对象方法</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> index</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> target</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> args</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">invoke</span><span class="params">(<span class="type">int</span> index, Object target, Object[] args)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (index == <span class="number">0</span>) &#123;</span><br><span class="line">            ((Target) target).save();</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (index == <span class="number">1</span>) &#123;</span><br><span class="line">            ((Target) target).save((<span class="type">int</span>) args[<span class="number">0</span>]);</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (index == <span class="number">2</span>) &#123;</span><br><span class="line">            ((Target) target).save((<span class="type">long</span>) args[<span class="number">0</span>]);</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">RuntimeException</span>(<span class="string">&quot;无此方法&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">TargetFastClass</span> <span class="variable">fastClass</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TargetFastClass</span>();</span><br><span class="line">        <span class="type">int</span> <span class="variable">index</span> <span class="operator">=</span> fastClass.getIndex(<span class="keyword">new</span> <span class="title class_">Signature</span>(<span class="string">&quot;save&quot;</span>, <span class="string">&quot;(I)V&quot;</span>));</span><br><span class="line">        fastClass.invoke(index, <span class="keyword">new</span> <span class="title class_">Target</span>(), <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="number">100</span>&#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>method.invoke()</code>调用流程：</p>
<ol>
<li>当proxy被创建时，会<strong>初始化方法信息</strong>，创建<code>MethodProxy</code></li>
<li>调用<code>method.invoke(target, args)</code>时，会先根据签名获取index</li>
<li>根据传入的index，target，args参数调用<code>TargetFastClass</code>的<code>invoke()</code>方法</li>
</ol>
<h3 id="invokeSuper"><a href="#invokeSuper" class="headerlink" title="invokeSuper()"></a><strong>invokeSuper()</strong></h3><p>接下来模拟<code>method.invoke()</code>方法的实现，取名叫<code>ProxyFastClass</code>：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ProxyFastClass</span> &#123;</span><br><span class="line">    <span class="keyword">static</span> <span class="type">Signature</span> <span class="variable">s0</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Signature</span>(<span class="string">&quot;saveSuper&quot;</span>, <span class="string">&quot;()V&quot;</span>);</span><br><span class="line">    <span class="keyword">static</span> <span class="type">Signature</span> <span class="variable">s1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Signature</span>(<span class="string">&quot;saveSuper&quot;</span>, <span class="string">&quot;(I)V&quot;</span>);</span><br><span class="line">    <span class="keyword">static</span> <span class="type">Signature</span> <span class="variable">s2</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Signature</span>(<span class="string">&quot;saveSuper&quot;</span>, <span class="string">&quot;(J)V&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 根据方法信息获取代理方法的编号</span></span><br><span class="line"><span class="comment">     * Target</span></span><br><span class="line"><span class="comment">     *             saveSuper()              0</span></span><br><span class="line"><span class="comment">     *             saveSuper(int)           1</span></span><br><span class="line"><span class="comment">     *             saveSuper(long)          2</span></span><br><span class="line"><span class="comment">     * signature 包括方法名字、参数返回值</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> signature</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">getIndex</span><span class="params">(Signature signature)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (s0.equals(signature)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (s1.equals(signature)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (s2.equals(signature)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="number">2</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 根据方法编号, 正常调用目标对象方法</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> index</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> proxy</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> args</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">invoke</span><span class="params">(<span class="type">int</span> index, Object proxy, Object[] args)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (index == <span class="number">0</span>) &#123;</span><br><span class="line">            ((Proxy) proxy).saveSuper();</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (index == <span class="number">1</span>) &#123;</span><br><span class="line">            ((Proxy) proxy).saveSuper((<span class="type">int</span>) args[<span class="number">0</span>]);</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (index == <span class="number">2</span>) &#123;</span><br><span class="line">            ((Proxy) proxy).saveSuper((<span class="type">long</span>) args[<span class="number">0</span>]);</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">RuntimeException</span>(<span class="string">&quot;无此方法&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">ProxyFastClass</span> <span class="variable">fastClass</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ProxyFastClass</span>();</span><br><span class="line">        <span class="type">int</span> <span class="variable">index</span> <span class="operator">=</span> fastClass.getIndex(<span class="keyword">new</span> <span class="title class_">Signature</span>(<span class="string">&quot;saveSuper&quot;</span>, <span class="string">&quot;()V&quot;</span>));</span><br><span class="line">        System.out.println(index);</span><br><span class="line"></span><br><span class="line">        fastClass.invoke(index, <span class="keyword">new</span> <span class="title class_">Proxy</span>(), <span class="keyword">new</span> <span class="title class_">Object</span>[<span class="number">0</span>]);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>ProxyFastClass</code>的实现和<code>TargetFastClass</code>类似，只不过传入的参数是代理类本身，并且在<code>invoke()</code>方法中调用的是<code>invokeSuper()</code>方法(原始方法)。</p>
<p><code>method.invokeSuper()</code>调用流程：</p>
<ol>
<li>当proxy被创建时，会<strong>初始化方法信息</strong>，创建<code>MethodProxy</code></li>
<li>调用<code>method.invoke(proxy, args)</code>时，会先根据签名获取index</li>
<li>根据传入的<code>proxy</code>，<code>target</code>，<code>args</code>参数调用<code>ProxyFastClass</code>的<code>invokeSuper()</code>方法</li>
</ol>
<p><strong>jdk与cglib动态代理对比：</strong></p>
<ul>
<li><code>jdk</code>动态代理需要先预热16次，再进行优化，并且每个方法会生成一个代理类</li>
<li><code>cglib</code>动态代理直接就可以避免反射调用，并且一个类对应两个代理类(<code>FastClass</code>实现)</li>
</ul>
<h1 id="jdk和cglib的统一"><a href="#jdk和cglib的统一" class="headerlink" title="jdk和cglib的统一"></a>jdk和cglib的统一</h1><h2 id="spring的代理选择规则"><a href="#spring的代理选择规则" class="headerlink" title="spring的代理选择规则"></a>spring的代理选择规则</h2><p><code>aspect</code>切面与<code>advisor</code>切面的区别：</p>
<ol>
<li><code>aspect = 通知1(advice) +  切点1(pointcut)</code>，一个aspect类中可以定义多个通知和切点。</li>
<li><code>advisor</code>是更细粒度的切面，包含一个通知和切点</li>
<li><code>aspect</code>最终生效解析之前会被拆解成多个<code>advisor</code></li>
</ol>
<p>使用代理增强的步骤：</p>
<ol>
<li>备好切点</li>
<li>备好通知</li>
<li>备好切面</li>
<li>创建代理</li>
</ol>
<p>切点在spring中是用<code>org.springframework.aop.Pointcut</code>来表示：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Pointcut</span> &#123;</span><br><span class="line">    <span class="type">Pointcut</span> <span class="variable">TRUE</span> <span class="operator">=</span> TruePointcut.INSTANCE;</span><br><span class="line">    <span class="comment">// 进行类过滤</span></span><br><span class="line">    ClassFilter <span class="title function_">getClassFilter</span><span class="params">()</span>;</span><br><span class="line">    <span class="comment">// 进行方法匹配</span></span><br><span class="line">    MethodMatcher <span class="title function_">getMethodMatcher</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>可以看到比较常用的实现：</p>
<p><img src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%89%E7%AB%A0%E3%80%91%EF%BC%9AAOP/1.png" alt="img"></p>
<p>比较重要的通知<code>org.aopalliance.intercept.MethodInterceptor</code>：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@FunctionalInterface</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">MethodInterceptor</span> <span class="keyword">extends</span> <span class="title class_">Interceptor</span> &#123;</span><br><span class="line">    <span class="meta">@Nullable</span></span><br><span class="line">    Object <span class="title function_">invoke</span><span class="params">(<span class="meta">@Nonnull</span> MethodInvocation invocation)</span> <span class="keyword">throws</span> Throwable;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>代码演示：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A15</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="comment">// 1. 备好切点</span></span><br><span class="line">        <span class="type">AspectJExpressionPointcut</span> <span class="variable">pointcut</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AspectJExpressionPointcut</span>();</span><br><span class="line">        pointcut.setExpression(<span class="string">&quot;execution(* foo())&quot;</span>);</span><br><span class="line">        <span class="comment">// 2. 备好通知</span></span><br><span class="line">        <span class="type">MethodInterceptor</span> <span class="variable">advice</span> <span class="operator">=</span> invocation -&gt; &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;before...&quot;</span>);</span><br><span class="line">            <span class="comment">// 调用目标</span></span><br><span class="line">            <span class="type">Object</span> <span class="variable">result</span> <span class="operator">=</span> invocation.proceed(); </span><br><span class="line">            System.out.println(<span class="string">&quot;after...&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> result;</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="comment">// 3. 备好切面</span></span><br><span class="line">        <span class="type">DefaultPointcutAdvisor</span> <span class="variable">advisor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DefaultPointcutAdvisor</span>(pointcut, advice);</span><br><span class="line">        <span class="comment">// 4. 创建代理</span></span><br><span class="line">        <span class="type">Target2</span> <span class="variable">target</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Target2</span>();</span><br><span class="line">        <span class="type">ProxyFactory</span> <span class="variable">factory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ProxyFactory</span>();</span><br><span class="line">        factory.setTarget(target);</span><br><span class="line">        factory.addAdvisor(advisor);</span><br><span class="line">        <span class="comment">// 设置接口，使spring知道target实现了接口</span></span><br><span class="line">        factory.setInterfaces(target.getClass().getInterfaces());</span><br><span class="line">        <span class="comment">// 设置setProxyTargetClass值</span></span><br><span class="line">        factory.setProxyTargetClass(<span class="literal">false</span>);</span><br><span class="line">        <span class="type">Target2</span> <span class="variable">proxy</span> <span class="operator">=</span> (Target2) factory.getProxy();</span><br><span class="line">        System.out.println(proxy.getClass());</span><br><span class="line">        proxy.foo();</span><br><span class="line">        proxy.bar();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">interface</span> <span class="title class_">I1</span> &#123;</span><br><span class="line">        <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">void</span> <span class="title function_">bar</span><span class="params">()</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Target1</span> <span class="keyword">implements</span> <span class="title class_">I1</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;target1 foo&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">bar</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;target1 bar&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Target2</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;target2 foo&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">bar</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;target2 bar&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>spring的代理选择规则</strong></p>
<p><code>ProxyFactory</code>的间接父类中<code>ProxyConfig</code>有<code>proxyTargetClass</code>字段：</p>
<ol>
<li><code>proxyTargetClass = false</code>，目标实现了接口, 用 jdk 实现</li>
<li><code>proxyTargetClass = false</code>，目标没有实现接口, 用 cglib 实现</li>
<li><code>proxyTargetClass = true</code>， 总是使用 cglib 实现</li>
</ol>
<h2 id="底层的切点实现"><a href="#底层的切点实现" class="headerlink" title="底层的切点实现"></a>底层的切点实现</h2><p>介绍切点匹配的方法，编写两个示例类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">T1</span> &#123;</span><br><span class="line">    <span class="meta">@Transactional</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">bar</span><span class="params">()</span> &#123;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>创建启动类，根据<strong>表达式</strong>切入：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A16</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NoSuchMethodException &#123;</span><br><span class="line">        <span class="type">AspectJExpressionPointcut</span> <span class="variable">pt1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AspectJExpressionPointcut</span>();</span><br><span class="line">        pt1.setExpression(<span class="string">&quot;execution(* bar())&quot;</span>);</span><br><span class="line">        System.out.println(pt1.matches(T1.class.getMethod(<span class="string">&quot;foo&quot;</span>), T1.class));</span><br><span class="line">        System.out.println(pt1.matches(T1.class.getMethod(<span class="string">&quot;bar&quot;</span>), T1.class));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">false </span><br><span class="line">true</span><br></pre></td></tr></table></figure>

<p><code>foo()</code>方法没有被表达式匹配，<code>bar()</code>成功匹配。</p>
<p>创建启动类，根据<strong>注解</strong>切入：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A16</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NoSuchMethodException &#123;</span><br><span class="line">        <span class="type">AspectJExpressionPointcut</span> <span class="variable">pt2</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AspectJExpressionPointcut</span>();</span><br><span class="line">        pt2.setExpression(<span class="string">&quot;@annotation(org.springframework.transaction.annotation.Transactional)&quot;</span>);</span><br><span class="line">        System.out.println(pt2.matches(T1.class.getMethod(<span class="string">&quot;foo&quot;</span>), T1.class));</span><br><span class="line">        System.out.println(pt2.matches(T1.class.getMethod(<span class="string">&quot;bar&quot;</span>), T1.class));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">true</span><br><span class="line">false</span><br></pre></td></tr></table></figure>

<p><code>foo()</code>方法被注解匹配，<code>bar()</code>没有被匹配。</p>
<blockquote>
<p>@Transactional注解并不是使用AspectJExpressionPointcut这种方式来实现的</p>
</blockquote>
<p><code>@Transactional</code>注解有多种使用方式：</p>
<ol>
<li>加在方法上</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">T1</span> &#123;</span><br><span class="line">    <span class="meta">@Transactional</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ol>
<li>加在类上</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Transactional</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">T2</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ol>
<li>加载接口上，实现类实现了该接口的方法将会生效</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Transactional</span></span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">I3</span> &#123;</span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">T3</span> <span class="keyword">implements</span> <span class="title class_">I3</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>AspectJExpressionPointcut</code>没法处理<code>@Transactional</code>注解的这些场景，因此我们这里模拟解析<code>@Transactional</code>注解的实现：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A16</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NoSuchMethodException &#123;</span><br><span class="line">        <span class="type">StaticMethodMatcherPointcut</span> <span class="variable">pt3</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StaticMethodMatcherPointcut</span>() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">matches</span><span class="params">(Method method, Class&lt;?&gt; targetClass)</span> &#123;</span><br><span class="line">                <span class="comment">// 检查方法上是否加了 Transactional 注解</span></span><br><span class="line">                <span class="type">MergedAnnotations</span> <span class="variable">annotations</span> <span class="operator">=</span> MergedAnnotations.from(method);</span><br><span class="line">                <span class="keyword">if</span> (annotations.isPresent(Transactional.class)) &#123;</span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">// 查看类上是否加了 Transactional 注解 查看类上是否加了 Transactional 注解 搜索策略设置为TYPE_HIERARCHY会搜索本类、父类</span></span><br><span class="line">                annotations = MergedAnnotations.from(targetClass, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY);</span><br><span class="line">                <span class="keyword">if</span> (annotations.isPresent(Transactional.class)) &#123;</span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line"></span><br><span class="line">        System.out.println(pt3.matches(T1.class.getMethod(<span class="string">&quot;foo&quot;</span>), T1.class));</span><br><span class="line">        System.out.println(pt3.matches(T1.class.getMethod(<span class="string">&quot;bar&quot;</span>), T1.class));</span><br><span class="line">        System.out.println(pt3.matches(T2.class.getMethod(<span class="string">&quot;foo&quot;</span>), T2.class));</span><br><span class="line">        System.out.println(pt3.matches(T3.class.getMethod(<span class="string">&quot;foo&quot;</span>), T3.class));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">T1</span> &#123;</span><br><span class="line">        <span class="meta">@Transactional</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">bar</span><span class="params">()</span> &#123;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Transactional</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">T2</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Transactional</span></span><br><span class="line">    <span class="keyword">interface</span> <span class="title class_">I3</span> &#123;</span><br><span class="line">        <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">T3</span> <span class="keyword">implements</span> <span class="title class_">I3</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">true</span><br><span class="line">false</span><br><span class="line">true</span><br><span class="line">true</span><br></pre></td></tr></table></figure>

<h2 id="底层的切面实现"><a href="#底层的切面实现" class="headerlink" title="底层的切面实现"></a>底层的切面实现</h2><p>准备代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.springframework.aop.framework.autoproxy;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.aopalliance.intercept.MethodInterceptor;</span><br><span class="line"><span class="keyword">import</span> org.aspectj.lang.annotation.Aspect;</span><br><span class="line"><span class="keyword">import</span> org.aspectj.lang.annotation.Before;</span><br><span class="line"><span class="keyword">import</span> org.springframework.aop.Advisor;</span><br><span class="line"><span class="keyword">import</span> org.springframework.aop.aspectj.AspectJExpressionPointcut;</span><br><span class="line"><span class="keyword">import</span> org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;</span><br><span class="line"><span class="keyword">import</span> org.springframework.aop.support.DefaultPointcutAdvisor;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Configuration;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.ConfigurationClassPostProcessor;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.support.GenericApplicationContext;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.annotation.Order;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A17</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">GenericApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">GenericApplicationContext</span>();</span><br><span class="line">        context.registerBean(<span class="string">&quot;aspect1&quot;</span>, Aspect1.class);</span><br><span class="line">        context.registerBean(<span class="string">&quot;config&quot;</span>, Config.class);</span><br><span class="line">        context.registerBean(ConfigurationClassPostProcessor.class);</span><br><span class="line">        <span class="comment">// BeanPostProcessor</span></span><br><span class="line">        <span class="comment">// 创建 -&gt; (*) 依赖注入 -&gt; 初始化 (*)</span></span><br><span class="line">        context.refresh();</span><br><span class="line">        <span class="keyword">for</span> (String name : context.getBeanDefinitionNames()) &#123;</span><br><span class="line">            System.out.println(name);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Target1</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;target1 foo&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Target2</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">bar</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;target2 bar&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Aspect</span> <span class="comment">// 高级切面类</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Aspect1</span> &#123;</span><br><span class="line">        <span class="meta">@Before(&quot;execution(* foo())&quot;)</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before1</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;aspect1 before1...&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Before(&quot;execution(* foo())&quot;)</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before2</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;aspect1 before2...&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Configuration</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Config</span> &#123;</span><br><span class="line">        <span class="meta">@Bean</span> <span class="comment">// 低级切面</span></span><br><span class="line">        <span class="keyword">public</span> Advisor <span class="title function_">advisor3</span><span class="params">(MethodInterceptor advice3)</span> &#123;</span><br><span class="line">            <span class="type">AspectJExpressionPointcut</span> <span class="variable">pointcut</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AspectJExpressionPointcut</span>();</span><br><span class="line">            pointcut.setExpression(<span class="string">&quot;execution(* foo())&quot;</span>);</span><br><span class="line">            <span class="type">DefaultPointcutAdvisor</span> <span class="variable">advisor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DefaultPointcutAdvisor</span>(pointcut, advice3);</span><br><span class="line">            <span class="keyword">return</span> advisor;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="meta">@Bean</span></span><br><span class="line">        <span class="keyword">public</span> MethodInterceptor <span class="title function_">advice3</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> invocation -&gt; &#123;</span><br><span class="line">                System.out.println(<span class="string">&quot;advice3 before...&quot;</span>);</span><br><span class="line">                <span class="type">Object</span> <span class="variable">result</span> <span class="operator">=</span> invocation.proceed();</span><br><span class="line">                System.out.println(<span class="string">&quot;advice3 after...&quot;</span>);</span><br><span class="line">                <span class="keyword">return</span> result;</span><br><span class="line">            &#125;;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">aspect1</span><br><span class="line">config</span><br><span class="line">org.springframework.context.annotation.ConfigurationClassPostProcessor</span><br><span class="line">advisor3</span><br><span class="line">advice3</span><br></pre></td></tr></table></figure>

<h3 id="底层切面实现"><a href="#底层切面实现" class="headerlink" title="底层切面实现"></a>底层切面实现</h3><p>底层切面实现用的是<code>AnnotationAwareAspectJAutoProxyCreator</code>，<code>AnnotationAwareAspectJAutoProxyCreator</code>是一个Bean后处理器，它有两个作用：</p>
<ul>
<li>找到容器中所有的切面，如果是<code>@Aspect</code>这种高级切面，会将其转换为<code>advisor</code>低级切面</li>
<li>根据找到的切面创建代理对象</li>
</ul>
<p>查看其类图：</p>
<p><img src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%89%E7%AB%A0%E3%80%91%EF%BC%9AAOP/2.png" alt="img"></p>
<p>我们发现它实现了<code>BeanPostProcessor</code>接口，对<code>Bean</code>进行了增强。<code>AnnotationAwareAspectJAutoProxyCreator</code>主要是在<code>Bean</code><strong>依赖注入</strong>之前以及<strong>初始化</strong>之后进行了增强。它有两个比较重要的方法：</p>
<ul>
<li><code>findEligibleAdvisors()</code>：找到有资格的切面类，主要找的是<code>advisor</code>，如果是高级切面，会将其转换为低级切面</li>
<li><code>wrapIfNecessary()</code>：针对符合要求的切面类创建代理</li>
</ul>
<p>这两个方法都被<code>protected</code>方法修饰，因此我们把测试类放在<code>org.springframework.aop.framework.autoproxy</code>包内。</p>
<h4 id="findEligibleAdvisors"><a href="#findEligibleAdvisors" class="headerlink" title="findEligibleAdvisors()"></a>findEligibleAdvisors()</h4><p>此方法的功能是：根据给定的目标类型，查找与目标类型相匹配的所有切面。</p>
<p>添加代码进行测试：</p>
<p>首先将<code>AnnotationAwareAspectJAutoProxyCreator</code>类注入<code>spring</code>容器中：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);</span><br></pre></td></tr></table></figure>

<p>获取<code>AnnotationAwareAspectJAutoProxyCreator</code>，调用<code>findEligibleAdvisors()</code>方法，并打印切面</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">AnnotationAwareAspectJAutoProxyCreator</span> <span class="variable">creator</span> <span class="operator">=</span> context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);</span><br><span class="line">List&lt;Advisor&gt; advisors = creator.findEligibleAdvisors(Target1.class, <span class="string">&quot;target1&quot;</span>);</span><br><span class="line"><span class="keyword">for</span> (Advisor advisor : advisors) &#123;</span><br><span class="line">    System.out.println(advisor);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>查看控制台：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// spring给我们添加的切面</span></span><br><span class="line">org.springframework.aop.interceptor.ExposeInvocationInterceptor.ADVISOR</span><br><span class="line"><span class="comment">// 高级切面@Aspect转换后的低级切面，有两个。对应Aspect1类中的before1()方法和before2()方法</span></span><br><span class="line">InstantiationModelAwarePointcutAdvisor: expression [execution(* foo())]; advice method [<span class="keyword">public</span> <span class="keyword">void</span> org.springframework.aop.framework.autoproxy.A17$Aspect1.before1()]; perClauseKind=SINGLETON</span><br><span class="line">InstantiationModelAwarePointcutAdvisor: expression [execution(* foo())]; advice method [<span class="keyword">public</span> <span class="keyword">void</span> org.springframework.aop.framework.autoproxy.A17$Aspect1.before2()]; perClauseKind=SINGLETON</span><br><span class="line"><span class="comment">// 低级切面，我们自己创建的DefaultPointcutAdvisor</span></span><br><span class="line">org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.framework.autoproxy.A17$Config$$Lambda$<span class="number">117</span>/<span class="number">0x0000000800d64fc0</span>@558bdf1f]</span><br></pre></td></tr></table></figure>

<h4 id="wrapIfNecessary"><a href="#wrapIfNecessary" class="headerlink" title="wrapIfNecessary()"></a>wrapIfNecessary()</h4><p>此方法的功能是：是否有必要为我们的目标创建代理。</p>
<p>思路很简单：调用<code>findEligibleAdvisors()</code>方法，如果返回值为空，那么说明不需要为这个类创建代理，反之需要创建单例。</p>
<p>添加代码进行测试：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Object</span> <span class="variable">o1</span> <span class="operator">=</span> creator.wrapIfNecessary(<span class="keyword">new</span> <span class="title class_">Target1</span>(), <span class="string">&quot;target1&quot;</span>, <span class="string">&quot;target1&quot;</span>);</span><br><span class="line">System.out.println(o1.getClass());</span><br><span class="line"><span class="type">Object</span> <span class="variable">o2</span> <span class="operator">=</span> creator.wrapIfNecessary(<span class="keyword">new</span> <span class="title class_">Target2</span>(), <span class="string">&quot;target2&quot;</span>, <span class="string">&quot;target2&quot;</span>);</span><br><span class="line">System.out.println(o2.getClass());</span><br><span class="line">((Target1) o1).foo();</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">org</span>.springframework.aop.framework.autoproxy.A17$Target1$$EnhancerBySpringCGLIB$$253983d3</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">org</span>.springframework.aop.framework.autoproxy.A17$Target2</span><br><span class="line">aspect1 before1...</span><br><span class="line">aspect1 before2...</span><br><span class="line">advice3 before...</span><br><span class="line">target1 foo</span><br><span class="line">advice3 after...</span><br></pre></td></tr></table></figure>

<p>我们发现<code>Target1</code>类已经被代理，调用<code>foo()</code>方法也能看到对方法的增强。</p>
<h3 id="代理对象创建的时机"><a href="#代理对象创建的时机" class="headerlink" title="代理对象创建的时机"></a>代理对象创建的时机</h3><p>代理对象的创建位置在依赖注入之前或者是在初始化之后。</p>
<p>暂时无法在飞书文档外展示此内容</p>
<p>准备示例代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A17_1</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">GenericApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">GenericApplicationContext</span>();</span><br><span class="line">        context.registerBean(ConfigurationClassPostProcessor.class);</span><br><span class="line">        context.registerBean(Config.class);</span><br><span class="line">        context.refresh();</span><br><span class="line">        context.close();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Configuration</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Config</span> &#123;</span><br><span class="line">        <span class="meta">@Bean</span> <span class="comment">// 解析 @Aspect、产生代理</span></span><br><span class="line">        <span class="keyword">public</span> AnnotationAwareAspectJAutoProxyCreator <span class="title function_">annotationAwareAspectJAutoProxyCreator</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">AnnotationAwareAspectJAutoProxyCreator</span>();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Bean</span> <span class="comment">// 解析 @Autowired</span></span><br><span class="line">        <span class="keyword">public</span> AutowiredAnnotationBeanPostProcessor <span class="title function_">autowiredAnnotationBeanPostProcessor</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">AutowiredAnnotationBeanPostProcessor</span>();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Bean</span> <span class="comment">// 解析 @PostConstruct</span></span><br><span class="line">        <span class="keyword">public</span> CommonAnnotationBeanPostProcessor <span class="title function_">commonAnnotationBeanPostProcessor</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">CommonAnnotationBeanPostProcessor</span>();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Bean</span></span><br><span class="line">        <span class="keyword">public</span> Advisor <span class="title function_">advisor</span><span class="params">(MethodInterceptor advice)</span> &#123;</span><br><span class="line">            <span class="type">AspectJExpressionPointcut</span> <span class="variable">pointcut</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AspectJExpressionPointcut</span>();</span><br><span class="line">            pointcut.setExpression(<span class="string">&quot;execution(* foo())&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">DefaultPointcutAdvisor</span>(pointcut, advice);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Bean</span></span><br><span class="line">        <span class="keyword">public</span> MethodInterceptor <span class="title function_">advice</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> (MethodInvocation invocation) -&gt; &#123;</span><br><span class="line">                System.out.println(<span class="string">&quot;before...&quot;</span>);</span><br><span class="line">                <span class="keyword">return</span> invocation.proceed();</span><br><span class="line">            &#125;;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Bean</span></span><br><span class="line">        <span class="keyword">public</span> Bean1 <span class="title function_">bean1</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Bean1</span>();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Bean</span></span><br><span class="line">        <span class="keyword">public</span> Bean2 <span class="title function_">bean2</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Bean2</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Bean1</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">public</span> <span class="title function_">Bean1</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;Bean1()&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="meta">@PostConstruct</span> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;Bean1 init()&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Bean2</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> <span class="title function_">Bean2</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;Bean2()&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="meta">@Autowired</span> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setBean1</span><span class="params">(Bean1 bean1)</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;Bean2 setBean1(bean1) class is: &quot;</span> + bean1.getClass());</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="meta">@PostConstruct</span> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;Bean2 init()&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>上述代码Bean2依赖注入了Bean1。</p>
</blockquote>
<p>查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">[INFO ] 21:59:12.415 [main] o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean &#x27;org.springframework.aop.framework.autoproxy.A17_1$Config&#x27; of type [org.springframework.aop.framework.autoproxy.A17_1$Config$$EnhancerBySpringCGLIB$$4ebf3912] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) </span><br><span class="line">[TRACE] 21:59:12.474 [main] o.s.a.a.a.AnnotationAwareAspectJAutoProxyCreator - Did not attempt to auto-proxy infrastructure class [org.springframework.aop.Advisor] </span><br><span class="line">[TRACE] 21:59:12.476 [main] o.s.a.a.a.AnnotationAwareAspectJAutoProxyCreator - Did not attempt to auto-proxy infrastructure class [org.aopalliance.intercept.MethodInterceptor] </span><br><span class="line">Bean1()</span><br><span class="line">Bean1 init()</span><br><span class="line">[TRACE] 21:59:12.575 [main] o.s.a.a.a.AnnotationAwareAspectJAutoProxyCreator - Creating implicit proxy for bean &#x27;bean1&#x27; with 0 common interceptors and 2 specific interceptors </span><br><span class="line">Bean2()</span><br><span class="line">Bean2 setBean1(bean1) class is: class org.springframework.aop.framework.autoproxy.A17_1$Bean1$$EnhancerBySpringCGLIB$$2d106fac</span><br><span class="line">Bean2 init()</span><br></pre></td></tr></table></figure>

<p>发现<code>Bean1</code>的代理对象是在初始化之后被创建的。</p>
<p>更改<code>Bean1</code>类，使其与<code>Bean2</code>循环依赖：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Bean1</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">Bean1</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;Bean1()&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Autowired</span> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setBean2</span><span class="params">(Bean2 bean2)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;Bean1 setBean2(bean2) class is: &quot;</span> + bean2.getClass());</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@PostConstruct</span> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;Bean1 init()&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">[INFO ] 22:02:35.788 [main] o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean &#x27;org.springframework.aop.framework.autoproxy.A17_1$Config&#x27; of type [org.springframework.aop.framework.autoproxy.A17_1$Config$$EnhancerBySpringCGLIB$$4ebf3912] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) </span><br><span class="line">[TRACE] 22:02:35.850 [main] o.s.a.a.a.AnnotationAwareAspectJAutoProxyCreator - Did not attempt to auto-proxy infrastructure class [org.springframework.aop.Advisor] </span><br><span class="line">[TRACE] 22:02:35.852 [main] o.s.a.a.a.AnnotationAwareAspectJAutoProxyCreator - Did not attempt to auto-proxy infrastructure class [org.aopalliance.intercept.MethodInterceptor] </span><br><span class="line">Bean1()</span><br><span class="line">Bean2()</span><br><span class="line">[TRACE] 22:02:36.015 [main] o.s.a.a.a.AnnotationAwareAspectJAutoProxyCreator - Creating implicit proxy for bean &#x27;bean1&#x27; with 0 common interceptors and 2 specific interceptors </span><br><span class="line">Bean2 setBean1(bean1) class is: class org.springframework.aop.framework.autoproxy.A17_1$Bean1$$EnhancerBySpringCGLIB$$2741d750</span><br><span class="line">Bean2 init()</span><br><span class="line">Bean1 setBean2(bean2) class is: class org.springframework.aop.framework.autoproxy.A17_1$Bean2</span><br><span class="line">Bean1 init()</span><br></pre></td></tr></table></figure>

<p>发现<code>Bean1</code>代理对象的创建提前在<code>Bean1</code>初始化之前了，这是因为<code>Bean2</code>需要注入的使<code>Bean1</code>的代理对象，而不是原始对象。</p>
<p><strong>总结：</strong></p>
<ol>
<li>代理的创建时机<ol>
<li>初始化之后 (无循环依赖时)</li>
<li>实例创建后, 依赖注入前 (有循环依赖时), 并暂存于二级缓存</li>
</ol>
</li>
<li>依赖注入与初始化不应该被增强, 仍应被施加于原始对象</li>
</ol>
<h3 id="高级切面转换为低级切面"><a href="#高级切面转换为低级切面" class="headerlink" title="高级切面转换为低级切面"></a>高级切面转换为低级切面</h3><p>在<code>findEligibleAdvisors()</code>方法执行时，会将遇到的<code>Aspect</code>切面转换为<code>advisor</code>的实现，这里介绍将高级切面转换为低级切面的过程。</p>
<p>编写示例代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A17_2</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Aspect</span> &#123;</span><br><span class="line">        <span class="meta">@Before(&quot;execution(* foo())&quot;)</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before1</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;before1&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Before(&quot;execution(* foo())&quot;)</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before2</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;before2&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">after</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;after&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">afterReturning</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;afterReturning&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">afterThrowing</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;afterThrowing&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> Object <span class="title function_">around</span><span class="params">(ProceedingJoinPoint pjp)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                System.out.println(<span class="string">&quot;around...before&quot;</span>);</span><br><span class="line">                <span class="keyword">return</span> pjp.proceed();</span><br><span class="line">            &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                System.out.println(<span class="string">&quot;around...after&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Target</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;target foo&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@SuppressWarnings(&quot;all&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line"></span><br><span class="line">        <span class="type">AspectInstanceFactory</span> <span class="variable">factory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SingletonAspectInstanceFactory</span>(<span class="keyword">new</span> <span class="title class_">Aspect</span>());</span><br><span class="line">        <span class="comment">// 高级切面转低级切面类</span></span><br><span class="line">        List&lt;Advisor&gt; list = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">        <span class="keyword">for</span> (Method method : Aspect.class.getDeclaredMethods()) &#123;</span><br><span class="line">            <span class="keyword">if</span> (method.isAnnotationPresent(Before.class)) &#123;</span><br><span class="line">                <span class="comment">// 解析切点</span></span><br><span class="line">                <span class="type">String</span> <span class="variable">expression</span> <span class="operator">=</span> method.getAnnotation(Before.class).value();</span><br><span class="line">                <span class="type">AspectJExpressionPointcut</span> <span class="variable">pointcut</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AspectJExpressionPointcut</span>();</span><br><span class="line">                pointcut.setExpression(expression);</span><br><span class="line">                <span class="comment">// 通知类</span></span><br><span class="line">                <span class="type">AspectJMethodBeforeAdvice</span> <span class="variable">advice</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AspectJMethodBeforeAdvice</span>(method, pointcut, factory);</span><br><span class="line">                <span class="comment">// 切面</span></span><br><span class="line">                <span class="type">Advisor</span> <span class="variable">advisor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DefaultPointcutAdvisor</span>(pointcut, advice);</span><br><span class="line">                list.add(advisor);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (Advisor advisor : list) &#123;</span><br><span class="line">            System.out.println(advisor);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>@Before</code>前置通知会被转换为原始的 <code>AspectJMethodBeforeAdvice </code>形式，该对象包含了如下信息：</p>
<ol>
<li>通知代码从哪儿来</li>
<li>切点是什么</li>
<li>通知对象如何创建, 本例共用同一个<code>Aspect</code>对象</li>
</ol>
<p>除了<code>AspectJMethodBeforeAdvice</code>，类似的通知还有：</p>
<ol>
<li><code>AspectJAroundAdvice </code>(环绕通知)</li>
<li><code>AspectJAfterReturningAdvice</code></li>
<li><code>AspectJAfterThrowingAdvice</code></li>
<li><code>AspectJAfterAdvice </code>(环绕通知)</li>
</ol>
<h3 id="Order注解"><a href="#Order注解" class="headerlink" title="@Order注解"></a>@Order注解</h3><p>编写示例代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A17</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">GenericApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">GenericApplicationContext</span>();</span><br><span class="line">        context.registerBean(<span class="string">&quot;aspect1&quot;</span>, Aspect1.class);</span><br><span class="line">        context.registerBean(<span class="string">&quot;config&quot;</span>, Config.class);</span><br><span class="line">        context.registerBean(ConfigurationClassPostProcessor.class);</span><br><span class="line">        context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);</span><br><span class="line">        context.refresh();</span><br><span class="line">        <span class="type">Object</span> <span class="variable">o1</span> <span class="operator">=</span> creator.wrapIfNecessary(<span class="keyword">new</span> <span class="title class_">Target1</span>(), <span class="string">&quot;target1&quot;</span>, <span class="string">&quot;target1&quot;</span>);</span><br><span class="line">        ((Target1) o1).foo();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Target1</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;target1 foo&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Target2</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">bar</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;target2 bar&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Aspect</span> <span class="comment">// 高级切面类</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Aspect1</span> &#123;</span><br><span class="line">        <span class="meta">@Before(&quot;execution(* foo())&quot;)</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before1</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;aspect1 before1...&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">       <span class="meta">@After(&quot;execution(* foo())&quot;)</span></span><br><span class="line">       <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before2</span><span class="params">()</span> &#123;</span><br><span class="line">           System.out.println(<span class="string">&quot;aspect1 after1...&quot;</span>);</span><br><span class="line">       &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Configuration</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Config</span> &#123;</span><br><span class="line">        <span class="meta">@Bean</span> <span class="comment">// 低级切面</span></span><br><span class="line">        <span class="keyword">public</span> Advisor <span class="title function_">advisor3</span><span class="params">(MethodInterceptor advice3)</span> &#123;</span><br><span class="line">            <span class="type">AspectJExpressionPointcut</span> <span class="variable">pointcut</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AspectJExpressionPointcut</span>();</span><br><span class="line">            pointcut.setExpression(<span class="string">&quot;execution(* foo())&quot;</span>);</span><br><span class="line">            <span class="type">DefaultPointcutAdvisor</span> <span class="variable">advisor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DefaultPointcutAdvisor</span>(pointcut, advice3);</span><br><span class="line">            <span class="keyword">return</span> advisor;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="meta">@Bean</span></span><br><span class="line">        <span class="keyword">public</span> MethodInterceptor <span class="title function_">advice3</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> invocation -&gt; &#123;</span><br><span class="line">                System.out.println(<span class="string">&quot;advice3 before...&quot;</span>);</span><br><span class="line">                <span class="type">Object</span> <span class="variable">result</span> <span class="operator">=</span> invocation.proceed();</span><br><span class="line">                System.out.println(<span class="string">&quot;advice3 after...&quot;</span>);</span><br><span class="line">                <span class="keyword">return</span> result;</span><br><span class="line">            &#125;;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">advice3 before...</span><br><span class="line">aspect1 before1...</span><br><span class="line">target1 foo</span><br><span class="line">aspect1 after1...</span><br><span class="line">advice3 after...</span><br></pre></td></tr></table></figure>

<p>我们发现默认<code>advisor</code>实现的代理先执行，<code>@Aspect</code>注解实现的代理后执行，对于<code>@Aspect</code>切面方式来讲，我们可以使用<code>@Order</code>注解调整代理的优先级：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Aspect</span> <span class="comment">// 高级切面类</span></span><br><span class="line"><span class="meta">@Order(1)</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Aspect1</span> &#123;</span><br><span class="line">    <span class="meta">@Before(&quot;execution(* foo())&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before1</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;aspect1 before1...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@After(&quot;execution(* foo())&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before2</span><span class="params">()</span> &#123;</span><br><span class="line">       System.out.println(<span class="string">&quot;aspect1 after1...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">aspect1 before1...</span><br><span class="line">advice3 before...</span><br><span class="line">target1 foo</span><br><span class="line">advice3 after...</span><br><span class="line">aspect1 after1...</span><br></pre></td></tr></table></figure>

<p>对于<code>advisor</code>切面方式，我们可以使用<code>setOrder()</code>方法设置优先级：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Config</span> &#123;</span><br><span class="line">    <span class="meta">@Bean</span> <span class="comment">// 低级切面</span></span><br><span class="line">    <span class="keyword">public</span> Advisor <span class="title function_">advisor3</span><span class="params">(MethodInterceptor advice3)</span> &#123;</span><br><span class="line">        <span class="type">AspectJExpressionPointcut</span> <span class="variable">pointcut</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AspectJExpressionPointcut</span>();</span><br><span class="line">        pointcut.setExpression(<span class="string">&quot;execution(* foo())&quot;</span>);</span><br><span class="line">        <span class="type">DefaultPointcutAdvisor</span> <span class="variable">advisor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DefaultPointcutAdvisor</span>(pointcut, advice3);</span><br><span class="line">        advisor.setOrder(<span class="number">1</span>);</span><br><span class="line">        <span class="keyword">return</span> advisor;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> MethodInterceptor <span class="title function_">advice3</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> invocation -&gt; &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;advice3 before...&quot;</span>);</span><br><span class="line">            <span class="type">Object</span> <span class="variable">result</span> <span class="operator">=</span> invocation.proceed();</span><br><span class="line">            System.out.println(<span class="string">&quot;advice3 after...&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> result;</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">advice3 before...</span><br><span class="line">aspect1 before1...</span><br><span class="line">target1 foo</span><br><span class="line">aspect1 after1...</span><br><span class="line">advice3 after...</span><br></pre></td></tr></table></figure>

<p><strong>缺点：</strong></p>
<ul>
<li><code>@Order</code>注解只能加在@Aspect 类上</li>
<li>类中所有方法的<code>order</code>权值都相同</li>
</ul>
<h2 id="底层的通知实现"><a href="#底层的通知实现" class="headerlink" title="底层的通知实现"></a>底层的通知实现</h2><h3 id="统一转换为环绕通知"><a href="#统一转换为环绕通知" class="headerlink" title="统一转换为环绕通知"></a>统一转换为环绕通知</h3><p>其实无论<code>ProxyFactory</code>基于哪种方式创建代理, 最后干活(调用<code>advice</code>)的是一个<code>MethodInvocation</code>对象</p>
<ol>
<li>因为<code>advisor</code>有多个, 且一个套一个调用, 因此需要一个调用链对象, 即<code>MethodInvocation</code></li>
<li><code>MethodInvocation</code>要知道<code>advice</code>有哪些, 还要知道目标, 调用次序如下</li>
</ol>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">将 MethodInvocation 放入当前线程</span><br><span class="line">    |-&gt; before1 ----------------------------------- 从当前线程获取 MethodInvocation</span><br><span class="line">    |                                             |</span><br><span class="line">    |   |-&gt; before2 --------------------          | 从当前线程获取 MethodInvocation</span><br><span class="line">    |   |                              |          |</span><br><span class="line">    |   |   |-&gt; target ------ 目标   advice2    advice1</span><br><span class="line">    |   |                              |          |</span><br><span class="line">    |   |-&gt; after2 ---------------------          |</span><br><span class="line">    |                                             |</span><br><span class="line">    |-&gt; after1 ------------------------------------</span><br></pre></td></tr></table></figure>

<blockquote>
<p>从上图看出, 环绕通知才适合作为 advice, 因此其他 before、afterReturning 都会被转换成环绕通知</p>
</blockquote>
<p>统一转换为环绕通知, 体现的是设计模式中的适配器模式：</p>
<ol>
<li>对外是为了方便使用要区分 before、afterReturning</li>
<li>对内统一都是环绕通知, 统一用 MethodInterceptor 表示</li>
</ol>
<p>示例代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A18</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Aspect</span> &#123;</span><br><span class="line">        <span class="meta">@Before(&quot;execution(* foo())&quot;)</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before1</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;before1&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Before(&quot;execution(* foo())&quot;)</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before2</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;before2&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">after</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;after&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@AfterReturning(&quot;execution(* foo())&quot;)</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">afterReturning</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;afterReturning&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@AfterThrowing(&quot;execution(* foo())&quot;)</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">afterThrowing</span><span class="params">(Exception e)</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;afterThrowing &quot;</span> + e.getMessage());</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Around(&quot;execution(* foo())&quot;)</span></span><br><span class="line">        <span class="keyword">public</span> Object <span class="title function_">around</span><span class="params">(ProceedingJoinPoint pjp)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                System.out.println(<span class="string">&quot;around...before&quot;</span>);</span><br><span class="line">                <span class="keyword">return</span> pjp.proceed();</span><br><span class="line">            &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                System.out.println(<span class="string">&quot;around...after&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Target</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;target foo&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@SuppressWarnings(&quot;all&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line"></span><br><span class="line">        <span class="type">AspectInstanceFactory</span> <span class="variable">factory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SingletonAspectInstanceFactory</span>(<span class="keyword">new</span> <span class="title class_">Aspect</span>());</span><br><span class="line">        <span class="comment">// 1. 高级切面转低级切面类</span></span><br><span class="line">        List&lt;Advisor&gt; list = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">        <span class="keyword">for</span> (Method method : Aspect.class.getDeclaredMethods()) &#123;</span><br><span class="line">            <span class="keyword">if</span> (method.isAnnotationPresent(Before.class)) &#123;</span><br><span class="line">                <span class="comment">// 解析切点</span></span><br><span class="line">                <span class="type">String</span> <span class="variable">expression</span> <span class="operator">=</span> method.getAnnotation(Before.class).value();</span><br><span class="line">                <span class="type">AspectJExpressionPointcut</span> <span class="variable">pointcut</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AspectJExpressionPointcut</span>();</span><br><span class="line">                pointcut.setExpression(expression);</span><br><span class="line">                <span class="comment">// 通知类</span></span><br><span class="line">                <span class="type">AspectJMethodBeforeAdvice</span> <span class="variable">advice</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AspectJMethodBeforeAdvice</span>(method, pointcut, factory);</span><br><span class="line">                <span class="comment">// 切面</span></span><br><span class="line">                <span class="type">Advisor</span> <span class="variable">advisor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DefaultPointcutAdvisor</span>(pointcut, advice);</span><br><span class="line">                list.add(advisor);</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (method.isAnnotationPresent(AfterReturning.class)) &#123;</span><br><span class="line">                <span class="comment">// 解析切点</span></span><br><span class="line">                <span class="type">String</span> <span class="variable">expression</span> <span class="operator">=</span> method.getAnnotation(AfterReturning.class).value();</span><br><span class="line">                <span class="type">AspectJExpressionPointcut</span> <span class="variable">pointcut</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AspectJExpressionPointcut</span>();</span><br><span class="line">                pointcut.setExpression(expression);</span><br><span class="line">                <span class="comment">// 通知类</span></span><br><span class="line">                <span class="type">AspectJAfterReturningAdvice</span> <span class="variable">advice</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AspectJAfterReturningAdvice</span>(method, pointcut, factory);</span><br><span class="line">                <span class="comment">// 切面</span></span><br><span class="line">                <span class="type">Advisor</span> <span class="variable">advisor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DefaultPointcutAdvisor</span>(pointcut, advice);</span><br><span class="line">                list.add(advisor);</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (method.isAnnotationPresent(Around.class)) &#123;</span><br><span class="line">                <span class="comment">// 解析切点</span></span><br><span class="line">                <span class="type">String</span> <span class="variable">expression</span> <span class="operator">=</span> method.getAnnotation(Around.class).value();</span><br><span class="line">                <span class="type">AspectJExpressionPointcut</span> <span class="variable">pointcut</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AspectJExpressionPointcut</span>();</span><br><span class="line">                pointcut.setExpression(expression);</span><br><span class="line">                <span class="comment">// 通知类</span></span><br><span class="line">                <span class="type">AspectJAroundAdvice</span> <span class="variable">advice</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AspectJAroundAdvice</span>(method, pointcut, factory);</span><br><span class="line">                <span class="comment">// 切面</span></span><br><span class="line">                <span class="type">Advisor</span> <span class="variable">advisor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DefaultPointcutAdvisor</span>(pointcut, advice);</span><br><span class="line">                list.add(advisor);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (Advisor advisor : list) &#123;</span><br><span class="line">            System.out.println(advisor);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">Target</span> <span class="variable">target</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Target</span>();</span><br><span class="line">        <span class="type">ProxyFactory</span> <span class="variable">proxyFactory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ProxyFactory</span>();</span><br><span class="line">        proxyFactory.setTarget(target);</span><br><span class="line">        proxyFactory.addAdvisors(list);</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&quot;</span>);</span><br><span class="line">        List&lt;Object&gt; methodInterceptorList = proxyFactory.getInterceptorsAndDynamicInterceptionAdvice(Target.class.getMethod(<span class="string">&quot;foo&quot;</span>), Target.class);</span><br><span class="line">        <span class="keyword">for</span> (Object o : methodInterceptorList) &#123;</span><br><span class="line">            System.out.println(o);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice: advice method [public void org.springframework.aop.framework.A18$Aspect.before1()]; aspect name &#x27;&#x27;]</span><br><span class="line">org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJAfterReturningAdvice: advice method [public void org.springframework.aop.framework.A18$Aspect.afterReturning()]; aspect name &#x27;&#x27;]</span><br><span class="line">org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice: advice method [public void org.springframework.aop.framework.A18$Aspect.before2()]; aspect name &#x27;&#x27;]</span><br><span class="line">org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJAroundAdvice: advice method [public java.lang.Object org.springframework.aop.framework.A18$Aspect.around(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable]; aspect name &#x27;&#x27;]</span><br><span class="line">&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;</span><br><span class="line">org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor@52bf72b5</span><br><span class="line">org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor@37afeb11</span><br><span class="line">org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor@515aebb0</span><br><span class="line">org.springframework.aop.aspectj.AspectJAroundAdvice: advice method [public java.lang.Object org.springframework.aop.framework.A18$Aspect.around(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable]; aspect name &#x27;&#x27;</span><br></pre></td></tr></table></figure>

<p>我们发现<code>AspectJMethodBeforeAdvice</code>已经被转换为<code>MethodBeforeAdviceInterceptor</code>，<code>AspectJAfterReturningAdvice</code>被转换为<code>AfterReturningAdviceInterceptor</code>，<code>AspectJAroundAdvice</code>本身就是环绕通知，不用被转换。</p>
<p>事实上只要实现<code>MethodInterceptor</code>接口的都不用转换：</p>
<ol>
<li><code>AspectJMethodBeforeAdvice</code>(前置通知)：未实现<code>MethodInterceptor</code>接口。</li>
<li><code>AspectJAroundAdvice</code>(环绕通知)：实现了<code>MethodInterceptor</code>接口。</li>
<li><code>AspectJAfterReturningAdvice</code>：未实现<code>MethodInterceptor</code>接口。</li>
<li><code>AspectJAfterThrowingAdvice</code>：实现了<code>MethodInterceptor</code>接口。</li>
<li><code>AspectJAfterAdvice</code>：实现了<code>MethodInterceptor</code>接口。</li>
</ol>
<h3 id="适配器模式"><a href="#适配器模式" class="headerlink" title="适配器模式"></a>适配器模式</h3><p>对于通知解析，我们需要的是<code>MethodInterceptor</code>接口，但解析后可能是另外的接口，因此需要将不符合<code>MethodInterceptor</code>接口的类转换为实现<code>MethodInterceptor</code>接口的类，这就需要使用到适配器模式。</p>
<ol>
<li>统一转换为 <code>MethodInterceptor</code>环绕通知, 这体现在方法名中的<code>Interceptors</code>上</li>
<li>适配如下：<ol>
<li><code>MethodBeforeAdviceAdapter</code>将<code>@Before</code> <code>AspectJMethodBeforeAdvice </code>适配为<code>MethodBeforeAdviceInterceptor</code></li>
<li><code>AfterReturningAdviceAdapter</code>将 <code>@AfterReturning</code> <code>AspectJAfterReturningAdvice</code>适配为 <code>AfterReturningAdviceInterceptor</code></li>
</ol>
</li>
</ol>
<p>我们可以查看<code>MethodBeforeAdviceAdapter</code>类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MethodBeforeAdviceAdapter</span> <span class="keyword">implements</span> <span class="title class_">AdvisorAdapter</span>, Serializable &#123;</span><br><span class="line">    MethodBeforeAdviceAdapter() &#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * 判断是否属于MethodBeforeAdvice </span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">supportsAdvice</span><span class="params">(Advice advice)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> advice <span class="keyword">instanceof</span> MethodBeforeAdvice;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * 将Advice转换为MethodInterceptor </span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">    <span class="keyword">public</span> MethodInterceptor <span class="title function_">getInterceptor</span><span class="params">(Advisor advisor)</span> &#123;</span><br><span class="line">        <span class="type">MethodBeforeAdvice</span> <span class="variable">advice</span> <span class="operator">=</span> (MethodBeforeAdvice)advisor.getAdvice();</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">MethodBeforeAdviceInterceptor</span>(advice);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>查看<code>AfterReturningAdviceAdapter</code>类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">AfterReturningAdviceAdapter</span> <span class="keyword">implements</span> <span class="title class_">AdvisorAdapter</span>, Serializable &#123;</span><br><span class="line">    AfterReturningAdviceAdapter() &#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * 判断是否属于AfterReturningAdvice</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">supportsAdvice</span><span class="params">(Advice advice)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> advice <span class="keyword">instanceof</span> AfterReturningAdvice;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * 将Advice转换为MethodInterceptor </span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">    <span class="keyword">public</span> MethodInterceptor <span class="title function_">getInterceptor</span><span class="params">(Advisor advisor)</span> &#123;</span><br><span class="line">        <span class="type">AfterReturningAdvice</span> <span class="variable">advice</span> <span class="operator">=</span> (AfterReturningAdvice)advisor.getAdvice();</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">AfterReturningAdviceInterceptor</span>(advice);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="调用链的执行"><a href="#调用链的执行" class="headerlink" title="调用链的执行"></a>调用链的执行</h3><p>通知统一转换为环绕通知之后，需要使用调用链来进行调用，调用链&#x3D;所有的环绕通知+目标。</p>
<p>添加调用链并执行：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 3. 创建并执行调用链 (环绕通知s + 目标)</span></span><br><span class="line"><span class="type">MethodInvocation</span> <span class="variable">methodInvocation</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ReflectiveMethodInvocation</span>(</span><br><span class="line">        <span class="literal">null</span>, target, Target.class.getMethod(<span class="string">&quot;foo&quot;</span>), <span class="keyword">new</span> <span class="title class_">Object</span>[<span class="number">0</span>], Target.class, methodInterceptorList</span><br><span class="line">);</span><br><span class="line">methodInvocation.proceed();</span><br></pre></td></tr></table></figure>

<p>运行后会发现报错：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Exception in thread &quot;main&quot; java.lang.IllegalStateException: No MethodInvocation found: Check that an AOP invocation is in progress and that the ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically, note that advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor! In addition, ExposeInvocationInterceptor and ExposeInvocationInterceptor.currentInvocation() must be invoked from the same thread.</span><br><span class="line">        at org.springframework.aop.interceptor.ExposeInvocationInterceptor.currentInvocation(ExposeInvocationInterceptor.java:74)</span><br><span class="line">        at org.springframework.aop.aspectj.AbstractAspectJAdvice.getJoinPointMatch(AbstractAspectJAdvice.java:658)</span><br><span class="line">        at org.springframework.aop.aspectj.AspectJMethodBeforeAdvice.before(AspectJMethodBeforeAdvice.java:44)</span><br><span class="line">        at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:57)</span><br><span class="line">        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)</span><br><span class="line">        at org.springframework.aop.framework.A18.main(A18.java:162)</span><br></pre></td></tr></table></figure>

<p>这是因为某些通知内部需要用到调用链对象，所以应该在最外层将调用链对象准备好，将 MethodInvocation 放入当前线程：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">proxyFactory.addAdvice(ExposeInvocationInterceptor.INSTANCE); <span class="comment">// 准备把 MethodInvocation 放入当前线程</span></span><br></pre></td></tr></table></figure>

<p>完整示例代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A18</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Aspect</span> &#123;</span><br><span class="line">        <span class="meta">@Before(&quot;execution(* foo())&quot;)</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before1</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;before1&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Before(&quot;execution(* foo())&quot;)</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before2</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;before2&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">after</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;after&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@AfterReturning(&quot;execution(* foo())&quot;)</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">afterReturning</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;afterReturning&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@AfterThrowing(&quot;execution(* foo())&quot;)</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">afterThrowing</span><span class="params">(Exception e)</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;afterThrowing &quot;</span> + e.getMessage());</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Around(&quot;execution(* foo())&quot;)</span></span><br><span class="line">        <span class="keyword">public</span> Object <span class="title function_">around</span><span class="params">(ProceedingJoinPoint pjp)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                System.out.println(<span class="string">&quot;around...before&quot;</span>);</span><br><span class="line">                <span class="keyword">return</span> pjp.proceed();</span><br><span class="line">            &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                System.out.println(<span class="string">&quot;around...after&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Target</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;target foo&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@SuppressWarnings(&quot;all&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line"></span><br><span class="line">        <span class="type">AspectInstanceFactory</span> <span class="variable">factory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SingletonAspectInstanceFactory</span>(<span class="keyword">new</span> <span class="title class_">Aspect</span>());</span><br><span class="line">        <span class="comment">// 1. 高级切面转低级切面类</span></span><br><span class="line">        List&lt;Advisor&gt; list = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">        <span class="keyword">for</span> (Method method : Aspect.class.getDeclaredMethods()) &#123;</span><br><span class="line">            <span class="keyword">if</span> (method.isAnnotationPresent(Before.class)) &#123;</span><br><span class="line">                <span class="comment">// 解析切点</span></span><br><span class="line">                <span class="type">String</span> <span class="variable">expression</span> <span class="operator">=</span> method.getAnnotation(Before.class).value();</span><br><span class="line">                <span class="type">AspectJExpressionPointcut</span> <span class="variable">pointcut</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AspectJExpressionPointcut</span>();</span><br><span class="line">                pointcut.setExpression(expression);</span><br><span class="line">                <span class="comment">// 通知类</span></span><br><span class="line">                <span class="type">AspectJMethodBeforeAdvice</span> <span class="variable">advice</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AspectJMethodBeforeAdvice</span>(method, pointcut, factory);</span><br><span class="line">                <span class="comment">// 切面</span></span><br><span class="line">                <span class="type">Advisor</span> <span class="variable">advisor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DefaultPointcutAdvisor</span>(pointcut, advice);</span><br><span class="line">                list.add(advisor);</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (method.isAnnotationPresent(AfterReturning.class)) &#123;</span><br><span class="line">                <span class="comment">// 解析切点</span></span><br><span class="line">                <span class="type">String</span> <span class="variable">expression</span> <span class="operator">=</span> method.getAnnotation(AfterReturning.class).value();</span><br><span class="line">                <span class="type">AspectJExpressionPointcut</span> <span class="variable">pointcut</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AspectJExpressionPointcut</span>();</span><br><span class="line">                pointcut.setExpression(expression);</span><br><span class="line">                <span class="comment">// 通知类</span></span><br><span class="line">                <span class="type">AspectJAfterReturningAdvice</span> <span class="variable">advice</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AspectJAfterReturningAdvice</span>(method, pointcut, factory);</span><br><span class="line">                <span class="comment">// 切面</span></span><br><span class="line">                <span class="type">Advisor</span> <span class="variable">advisor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DefaultPointcutAdvisor</span>(pointcut, advice);</span><br><span class="line">                list.add(advisor);</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (method.isAnnotationPresent(Around.class)) &#123;</span><br><span class="line">                <span class="comment">// 解析切点</span></span><br><span class="line">                <span class="type">String</span> <span class="variable">expression</span> <span class="operator">=</span> method.getAnnotation(Around.class).value();</span><br><span class="line">                <span class="type">AspectJExpressionPointcut</span> <span class="variable">pointcut</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AspectJExpressionPointcut</span>();</span><br><span class="line">                pointcut.setExpression(expression);</span><br><span class="line">                <span class="comment">// 通知类</span></span><br><span class="line">                <span class="type">AspectJAroundAdvice</span> <span class="variable">advice</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AspectJAroundAdvice</span>(method, pointcut, factory);</span><br><span class="line">                <span class="comment">// 切面</span></span><br><span class="line">                <span class="type">Advisor</span> <span class="variable">advisor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DefaultPointcutAdvisor</span>(pointcut, advice);</span><br><span class="line">                list.add(advisor);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (Advisor advisor : list) &#123;</span><br><span class="line">            System.out.println(advisor);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">Target</span> <span class="variable">target</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Target</span>();</span><br><span class="line">        <span class="type">ProxyFactory</span> <span class="variable">proxyFactory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ProxyFactory</span>();</span><br><span class="line">        proxyFactory.setTarget(target);</span><br><span class="line">        proxyFactory.addAdvice(ExposeInvocationInterceptor.INSTANCE); <span class="comment">// 准备把 MethodInvocation 放入当前线程</span></span><br><span class="line">        proxyFactory.addAdvisors(list);</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&quot;</span>);</span><br><span class="line">        List&lt;Object&gt; methodInterceptorList = proxyFactory.getInterceptorsAndDynamicInterceptionAdvice(Target.class.getMethod(<span class="string">&quot;foo&quot;</span>), Target.class);</span><br><span class="line">        <span class="keyword">for</span> (Object o : methodInterceptorList) &#123;</span><br><span class="line">            System.out.println(o);</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(<span class="string">&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&quot;</span>);</span><br><span class="line">        <span class="comment">// 3. 创建并执行调用链 (环绕通知s + 目标)</span></span><br><span class="line">        <span class="type">MethodInvocation</span> <span class="variable">methodInvocation</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ReflectiveMethodInvocation</span>(</span><br><span class="line">                <span class="literal">null</span>, target, Target.class.getMethod(<span class="string">&quot;foo&quot;</span>), <span class="keyword">new</span> <span class="title class_">Object</span>[<span class="number">0</span>], Target.class, methodInterceptorList</span><br><span class="line">        );</span><br><span class="line">        methodInvocation.proceed();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice: advice method [<span class="keyword">public</span> <span class="keyword">void</span> org.springframework.aop.framework.A18$Aspect.before1()]; aspect name <span class="string">&#x27;&#x27;</span>]</span><br><span class="line">org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice: advice method [<span class="keyword">public</span> <span class="keyword">void</span> org.springframework.aop.framework.A18$Aspect.before2()]; aspect name <span class="string">&#x27;&#x27;</span>]</span><br><span class="line">org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJAroundAdvice: advice method [<span class="keyword">public</span> java.lang.Object org.springframework.aop.framework.A18$Aspect.around(org.aspectj.lang.ProceedingJoinPoint) <span class="keyword">throws</span> java.lang.Throwable]; aspect name <span class="string">&#x27;&#x27;</span>]</span><br><span class="line">org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJAfterReturningAdvice: advice method [<span class="keyword">public</span> <span class="keyword">void</span> org.springframework.aop.framework.A18$Aspect.afterReturning()]; aspect name <span class="string">&#x27;&#x27;</span>]</span><br><span class="line">&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;</span><br><span class="line">org.springframework.aop.interceptor.ExposeInvocationInterceptor@1d2adfbe</span><br><span class="line">org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor@<span class="number">36902638</span></span><br><span class="line">org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor@223d2c72</span><br><span class="line">org.springframework.aop.aspectj.AspectJAroundAdvice: advice method [<span class="keyword">public</span> java.lang.Object org.springframework.aop.framework.A18$Aspect.around(org.aspectj.lang.ProceedingJoinPoint) <span class="keyword">throws</span> java.lang.Throwable]; aspect name <span class="string">&#x27;&#x27;</span></span><br><span class="line">org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor@8f4ea7c</span><br><span class="line">&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;</span><br><span class="line">before1</span><br><span class="line">before2</span><br><span class="line">around...before</span><br><span class="line">target foo</span><br><span class="line">afterReturning</span><br><span class="line">around...after</span><br></pre></td></tr></table></figure>

<p>成功执行了调用链。</p>
<h3 id="模拟实现调用链"><a href="#模拟实现调用链" class="headerlink" title="模拟实现调用链"></a>模拟实现调用链</h3><p>调用链实际上是使用的责任链模式，示例代码实现：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 模拟调用链过程, 是一个简单的递归过程</span></span><br><span class="line"><span class="comment"> *         1. proceed() 方法调用链中下一个环绕通知</span></span><br><span class="line"><span class="comment"> *         2. 每个环绕通知内部继续调用 proceed()</span></span><br><span class="line"><span class="comment"> *         3. 调用到没有更多通知了, 就调用目标方法</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A18_1</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Target</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;Target.foo()&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Advice1</span> <span class="keyword">implements</span> <span class="title class_">MethodInterceptor</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> Object <span class="title function_">invoke</span><span class="params">(MethodInvocation invocation)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;Advice1.before()&quot;</span>);</span><br><span class="line">            <span class="type">Object</span> <span class="variable">result</span> <span class="operator">=</span> invocation.proceed();<span class="comment">// 调用下一个通知或目标</span></span><br><span class="line">            System.out.println(<span class="string">&quot;Advice1.after()&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> result;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Advice2</span> <span class="keyword">implements</span> <span class="title class_">MethodInterceptor</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> Object <span class="title function_">invoke</span><span class="params">(MethodInvocation invocation)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;Advice2.before()&quot;</span>);</span><br><span class="line">            <span class="type">Object</span> <span class="variable">result</span> <span class="operator">=</span> invocation.proceed();<span class="comment">// 调用下一个通知或目标</span></span><br><span class="line">            System.out.println(<span class="string">&quot;Advice2.after()&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> result;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">MyInvocation</span> <span class="keyword">implements</span> <span class="title class_">MethodInvocation</span> &#123;</span><br><span class="line">        <span class="keyword">private</span> Object target;  <span class="comment">// 1</span></span><br><span class="line">        <span class="keyword">private</span> Method method;</span><br><span class="line">        <span class="keyword">private</span> Object[] args;</span><br><span class="line">        List&lt;MethodInterceptor&gt; methodInterceptorList; <span class="comment">// 2</span></span><br><span class="line">        <span class="keyword">private</span> <span class="type">int</span> <span class="variable">count</span> <span class="operator">=</span> <span class="number">1</span>; <span class="comment">// 调用次数</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> <span class="title function_">MyInvocation</span><span class="params">(Object target, Method method, Object[] args, List&lt;MethodInterceptor&gt; methodInterceptorList)</span> &#123;</span><br><span class="line">            <span class="built_in">this</span>.target = target;</span><br><span class="line">            <span class="built_in">this</span>.method = method;</span><br><span class="line">            <span class="built_in">this</span>.args = args;</span><br><span class="line">            <span class="built_in">this</span>.methodInterceptorList = methodInterceptorList;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="keyword">public</span> Method <span class="title function_">getMethod</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> method;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="keyword">public</span> Object[] getArguments() &#123;</span><br><span class="line">            <span class="keyword">return</span> args;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="keyword">public</span> Object <span class="title function_">proceed</span><span class="params">()</span> <span class="keyword">throws</span> Throwable &#123; <span class="comment">// 调用每一个环绕通知, 调用目标</span></span><br><span class="line">            <span class="keyword">if</span> (count &gt; methodInterceptorList.size()) &#123;</span><br><span class="line">                <span class="comment">// 调用目标， 返回并结束递归</span></span><br><span class="line">                <span class="keyword">return</span> method.invoke(target, args);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// 逐一调用通知, count + 1</span></span><br><span class="line">            <span class="type">MethodInterceptor</span> <span class="variable">methodInterceptor</span> <span class="operator">=</span> methodInterceptorList.get(count++ - <span class="number">1</span>);</span><br><span class="line">            <span class="keyword">return</span> methodInterceptor.invoke(<span class="built_in">this</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="keyword">public</span> Object <span class="title function_">getThis</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> target;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="keyword">public</span> AccessibleObject <span class="title function_">getStaticPart</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> method;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">        <span class="type">Target</span> <span class="variable">target</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Target</span>();</span><br><span class="line">        List&lt;MethodInterceptor&gt; list = List.of(</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">Advice1</span>(),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">Advice2</span>()</span><br><span class="line">        );</span><br><span class="line">        <span class="type">MyInvocation</span> <span class="variable">invocation</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MyInvocation</span>(target, Target.class.getMethod(<span class="string">&quot;foo&quot;</span>), <span class="keyword">new</span> <span class="title class_">Object</span>[<span class="number">0</span>], list);</span><br><span class="line">        invocation.proceed();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Advice1.before()</span><br><span class="line">Advice2.before()</span><br><span class="line">Target.foo()</span><br><span class="line">Advice2.after()</span><br><span class="line">Advice1.after()</span><br></pre></td></tr></table></figure>

<h3 id="动态通知调用"><a href="#动态通知调用" class="headerlink" title="动态通知调用"></a>动态通知调用</h3><p>静态通知与动态通知对比：</p>
<ol>
<li>静态通知调用，不带参数绑定，执行时不需要切点</li>
<li>动态通知调用，需要参数绑定，执行时还需要切点对象</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Aspect</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">MyAspect</span> &#123;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * 静态通知调用</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">    <span class="meta">@Before(&quot;execution(* foo(..))&quot;)</span> <span class="comment">// </span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before1</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;before1&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * 动态通知调用</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">    <span class="meta">@Before(&quot;execution(* foo(..)) &amp;&amp; args(x)&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before2</span><span class="params">(<span class="type">int</span> x)</span> &#123;</span><br><span class="line">        System.out.printf(<span class="string">&quot;before2(%d)%n&quot;</span>, x);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>示例代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A19</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Aspect</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">MyAspect</span> &#123;</span><br><span class="line">        <span class="meta">@Before(&quot;execution(* foo(..))&quot;)</span> <span class="comment">// 静态通知调用，不带参数绑定，执行时不需要切点</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before1</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;before1&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Before(&quot;execution(* foo(..)) &amp;&amp; args(x)&quot;)</span> <span class="comment">// 动态通知调用，需要参数绑定，执行时还需要切点对象</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">before2</span><span class="params">(<span class="type">int</span> x)</span> &#123;</span><br><span class="line">            System.out.printf(<span class="string">&quot;before2(%d)%n&quot;</span>, x);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Target</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">(<span class="type">int</span> x)</span> &#123;</span><br><span class="line">            System.out.printf(<span class="string">&quot;target foo(%d)%n&quot;</span>, x);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Configuration</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">MyConfig</span> &#123;</span><br><span class="line">        <span class="meta">@Bean</span></span><br><span class="line">        AnnotationAwareAspectJAutoProxyCreator <span class="title function_">proxyCreator</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">AnnotationAwareAspectJAutoProxyCreator</span>();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Bean</span></span><br><span class="line">        <span class="keyword">public</span> MyAspect <span class="title function_">myAspect</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">MyAspect</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">        <span class="type">GenericApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">GenericApplicationContext</span>();</span><br><span class="line">        context.registerBean(ConfigurationClassPostProcessor.class);</span><br><span class="line">        context.registerBean(MyConfig.class);</span><br><span class="line">        context.refresh();</span><br><span class="line"></span><br><span class="line">        <span class="type">AnnotationAwareAspectJAutoProxyCreator</span> <span class="variable">creator</span> <span class="operator">=</span> context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);</span><br><span class="line">        List&lt;Advisor&gt; list = creator.findEligibleAdvisors(Target.class, <span class="string">&quot;target&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="type">Target</span> <span class="variable">target</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Target</span>();</span><br><span class="line">        <span class="type">ProxyFactory</span> <span class="variable">factory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ProxyFactory</span>();</span><br><span class="line">        factory.setTarget(target);</span><br><span class="line">        factory.addAdvisors(list);</span><br><span class="line">        <span class="type">Object</span> <span class="variable">proxy</span> <span class="operator">=</span> factory.getProxy(); <span class="comment">// 获取代理</span></span><br><span class="line"></span><br><span class="line">        List&lt;Object&gt; interceptorList = factory.getInterceptorsAndDynamicInterceptionAdvice(Target.class.getMethod(<span class="string">&quot;foo&quot;</span>, <span class="type">int</span>.class), Target.class);</span><br><span class="line">        <span class="keyword">for</span> (Object o : interceptorList) &#123;</span><br><span class="line">            showDetail(o);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&quot;</span>);</span><br><span class="line">        <span class="type">ReflectiveMethodInvocation</span> <span class="variable">invocation</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ReflectiveMethodInvocation</span>(</span><br><span class="line">                proxy, target, Target.class.getMethod(<span class="string">&quot;foo&quot;</span>, <span class="type">int</span>.class), <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="number">100</span>&#125;, Target.class, interceptorList</span><br><span class="line">        ) &#123;&#125;;</span><br><span class="line"></span><br><span class="line">        invocation.proceed();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">showDetail</span><span class="params">(Object o)</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            Class&lt;?&gt; clazz = Class.forName(<span class="string">&quot;org.springframework.aop.framework.InterceptorAndDynamicMethodMatcher&quot;</span>);</span><br><span class="line">            <span class="keyword">if</span> (clazz.isInstance(o)) &#123;</span><br><span class="line">                <span class="type">Field</span> <span class="variable">methodMatcher</span> <span class="operator">=</span> clazz.getDeclaredField(<span class="string">&quot;methodMatcher&quot;</span>);</span><br><span class="line">                methodMatcher.setAccessible(<span class="literal">true</span>);</span><br><span class="line">                <span class="type">Field</span> <span class="variable">methodInterceptor</span> <span class="operator">=</span> clazz.getDeclaredField(<span class="string">&quot;interceptor&quot;</span>);</span><br><span class="line">                methodInterceptor.setAccessible(<span class="literal">true</span>);</span><br><span class="line">                System.out.println(<span class="string">&quot;环绕通知和切点：&quot;</span> + o);</span><br><span class="line">                System.out.println(<span class="string">&quot;\t切点为：&quot;</span> + methodMatcher.get(o));</span><br><span class="line">                System.out.println(<span class="string">&quot;\t通知为：&quot;</span> + methodInterceptor.get(o));</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                System.out.println(<span class="string">&quot;普通环绕通知：&quot;</span> + o);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">[INFO ] 16:25:32.123 [main] o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean &#x27;org.springframework.aop.framework.autoproxy.A19$MyConfig&#x27; of type [org.springframework.aop.framework.autoproxy.A19$MyConfig$$EnhancerBySpringCGLIB$$4d8924fd] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) </span><br><span class="line">普通环绕通知：org.springframework.aop.interceptor.ExposeInvocationInterceptor@63fbfaeb</span><br><span class="line">普通环绕通知：org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor@2c07545f</span><br><span class="line">环绕通知和切点：org.springframework.aop.framework.InterceptorAndDynamicMethodMatcher@e57b96d</span><br><span class="line">        切点为：AspectJExpressionPointcut: (int x) execution(* foo(..)) &amp;&amp; args(x)</span><br><span class="line">        通知为：org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor@34c01041</span><br><span class="line">&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;</span><br><span class="line">before1</span><br><span class="line">before2(100)</span><br><span class="line">target foo(100)</span><br></pre></td></tr></table></figure>

<p>进入<code>InterceptorAndDynamicMethodMatcher</code>中，我们发现它没有实现<code>MethodInterceptor</code>接口，但其成员变量却有：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 记录通知</span></span><br><span class="line"><span class="keyword">final</span> MethodInterceptor interceptor;</span><br><span class="line"><span class="comment">// 记录切点</span></span><br><span class="line"><span class="keyword">final</span> MethodMatcher methodMatcher;</span><br></pre></td></tr></table></figure>

<p>我们在使用<code>invocation</code>调用的时候，需要传入参数。</p>
<p><strong>总结：</strong></p>
<ol>
<li>有参数绑定的通知调用时还需要切点，对参数进行匹配及绑定</li>
<li>复杂程度高, 性能比无参数绑定的通知调用低</li>
</ol>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href>狼族少年、血狼</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://geekwolfman.github.io/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%89%E7%AB%A0%E3%80%91%EF%BC%9AAOP.html">https://geekwolfman.github.io/2023/04/15/Spring高级45讲【第三章】：AOP.html</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://geekwolfman.github.io" target="_blank">狼族少年、血狼</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/spring/">spring</a></div><div class="post_share"><div class="social-share" data-image="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%89%E7%AB%A0%E3%80%91%EF%BC%9AAOP/01cover.jpg" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/js/social-share.min.js" defer></script></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E5%9B%9B%E7%AB%A0%E3%80%91%EF%BC%9AWEB.html" title="Spring高级45讲【第四章】：WEB"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E5%9B%9B%E7%AB%A0%E3%80%91%EF%BC%9AWEB/01cover.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">Spring高级45讲【第四章】：WEB</div></div></a></div><div class="next-post pull-right"><a href="/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC.html" title="Spring高级45讲【第二章】：IOC"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC/01cover.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">Spring高级45讲【第二章】：IOC</div></div></a></div></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span>相关推荐</span></div><div class="relatedPosts-list"><div><a href="/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E5%85%AD%E7%AB%A0%E3%80%91%EF%BC%9AOTHER.html" title="Spring高级45讲【第六章】：OTHER"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E5%85%AD%E7%AB%A0%E3%80%91%EF%BC%9AOTHER/00cover.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-04-15</div><div class="title">Spring高级45讲【第六章】：OTHER</div></div></a></div><div><a href="/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%94%E7%AB%A0%E3%80%91%EF%BC%9ABOOT.html" title="Spring高级45讲【第五章】：BOOT"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%94%E7%AB%A0%E3%80%91%EF%BC%9ABOOT/01cover.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-04-15</div><div class="title">Spring高级45讲【第五章】：BOOT</div></div></a></div><div><a href="/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E5%9B%9B%E7%AB%A0%E3%80%91%EF%BC%9AWEB.html" title="Spring高级45讲【第四章】：WEB"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E5%9B%9B%E7%AB%A0%E3%80%91%EF%BC%9AWEB/01cover.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-04-15</div><div class="title">Spring高级45讲【第四章】：WEB</div></div></a></div><div><a href="/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC.html" title="Spring高级45讲【第二章】：IOC"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC/01cover.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-04-15</div><div class="title">Spring高级45讲【第二章】：IOC</div></div></a></div><div><a href="/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%80%E7%AB%A0%E3%80%91%EF%BC%9A%E5%AF%BC%E5%AD%A6.html" title="Spring高级45讲【第一章】：导学"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%80%E7%AB%A0%E3%80%91%EF%BC%9A%E5%AF%BC%E5%AD%A6/01cover.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-04-15</div><div class="title">Spring高级45讲【第一章】：导学</div></div></a></div><div><a href="/2023/03/23/%E6%89%8B%E5%86%99%E7%AE%80%E6%98%93%E7%89%88spring-web%E6%A1%86%E6%9E%B6.html" title="手写简易版spring web框架"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/%E6%89%8B%E5%86%99%E7%AE%80%E6%98%93%E7%89%88spring-web%E6%A1%86%E6%9E%B6/01cover.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-03-23</div><div class="title">手写简易版spring web框架</div></div></a></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/config/avatar/avatar.png" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="author-info__name">狼族少年、血狼</div><div class="author-info__description"></div></div><div class="card-info-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">57</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">14</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">9</div></a></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://wpa.qq.com/msgrd?v=3&amp;uin=2370032534&amp;site=qq&amp;menu=yes&amp;jumpflag=1"><i class="fa-brands fa-qq"></i><span>添加博主QQ</span></a></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">本站所有博文均是博主的学习笔记与个人理解，来源于网络，如有<span style="color:red;font-weight:bold;">侵权</span>请<a target="_blank" rel="noopener" href="https://wpa.qq.com/msgrd?v=3&uin=2370032534&site=qq&menu=yes&jumpflag=1" style="color:#49B1F5;font-weight:bold">联系我</a>进行删除🥰。</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%BB%A3%E7%90%86%E5%A2%9E%E5%BC%BA%E6%96%B9%E5%BC%8F"><span class="toc-number">1.</span> <span class="toc-text">代理增强方式</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#aspectj%E7%BC%96%E8%AF%91%E5%99%A8%E5%A2%9E%E5%BC%BA"><span class="toc-number">1.1.</span> <span class="toc-text">aspectj编译器增强</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#agent%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%A2%9E%E5%BC%BA"><span class="toc-number">1.2.</span> <span class="toc-text">agent类加载增强</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#jdk%E4%BB%A3%E7%90%86%E5%A2%9E%E5%BC%BA"><span class="toc-number">1.3.</span> <span class="toc-text">jdk代理增强</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#cglib%E4%BB%A3%E7%90%86%E5%A2%9E%E5%BC%BA"><span class="toc-number">1.4.</span> <span class="toc-text">cglib代理增强</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#jdk%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E5%8E%9F%E7%90%86"><span class="toc-number">2.</span> <span class="toc-text">jdk动态代理原理</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%A8%A1%E6%8B%9Fjdk%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86"><span class="toc-number">2.1.</span> <span class="toc-text">模拟jdk动态代理</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#jdk%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E6%BA%90%E7%A0%81"><span class="toc-number">2.2.</span> <span class="toc-text">jdk动态代理源码</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#jdk%E5%8F%8D%E5%B0%84%E4%BC%98%E5%8C%96"><span class="toc-number">2.3.</span> <span class="toc-text">jdk反射优化</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#cglib%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E5%8E%9F%E7%90%86"><span class="toc-number">3.</span> <span class="toc-text">cglib动态代理原理</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%A8%A1%E6%8B%9Fcglib%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86"><span class="toc-number">3.1.</span> <span class="toc-text">模拟cglib动态代理</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#MethodProxy%E5%8E%9F%E7%90%86"><span class="toc-number">3.2.</span> <span class="toc-text">MethodProxy原理</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#invoke"><span class="toc-number">3.2.1.</span> <span class="toc-text">invoke()</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#invokeSuper"><span class="toc-number">3.2.2.</span> <span class="toc-text">invokeSuper()</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#jdk%E5%92%8Ccglib%E7%9A%84%E7%BB%9F%E4%B8%80"><span class="toc-number">4.</span> <span class="toc-text">jdk和cglib的统一</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#spring%E7%9A%84%E4%BB%A3%E7%90%86%E9%80%89%E6%8B%A9%E8%A7%84%E5%88%99"><span class="toc-number">4.1.</span> <span class="toc-text">spring的代理选择规则</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%BA%95%E5%B1%82%E7%9A%84%E5%88%87%E7%82%B9%E5%AE%9E%E7%8E%B0"><span class="toc-number">4.2.</span> <span class="toc-text">底层的切点实现</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%BA%95%E5%B1%82%E7%9A%84%E5%88%87%E9%9D%A2%E5%AE%9E%E7%8E%B0"><span class="toc-number">4.3.</span> <span class="toc-text">底层的切面实现</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%BA%95%E5%B1%82%E5%88%87%E9%9D%A2%E5%AE%9E%E7%8E%B0"><span class="toc-number">4.3.1.</span> <span class="toc-text">底层切面实现</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#findEligibleAdvisors"><span class="toc-number">4.3.1.1.</span> <span class="toc-text">findEligibleAdvisors()</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#wrapIfNecessary"><span class="toc-number">4.3.1.2.</span> <span class="toc-text">wrapIfNecessary()</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BB%A3%E7%90%86%E5%AF%B9%E8%B1%A1%E5%88%9B%E5%BB%BA%E7%9A%84%E6%97%B6%E6%9C%BA"><span class="toc-number">4.3.2.</span> <span class="toc-text">代理对象创建的时机</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%AB%98%E7%BA%A7%E5%88%87%E9%9D%A2%E8%BD%AC%E6%8D%A2%E4%B8%BA%E4%BD%8E%E7%BA%A7%E5%88%87%E9%9D%A2"><span class="toc-number">4.3.3.</span> <span class="toc-text">高级切面转换为低级切面</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Order%E6%B3%A8%E8%A7%A3"><span class="toc-number">4.3.4.</span> <span class="toc-text">@Order注解</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%BA%95%E5%B1%82%E7%9A%84%E9%80%9A%E7%9F%A5%E5%AE%9E%E7%8E%B0"><span class="toc-number">4.4.</span> <span class="toc-text">底层的通知实现</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BB%9F%E4%B8%80%E8%BD%AC%E6%8D%A2%E4%B8%BA%E7%8E%AF%E7%BB%95%E9%80%9A%E7%9F%A5"><span class="toc-number">4.4.1.</span> <span class="toc-text">统一转换为环绕通知</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%80%82%E9%85%8D%E5%99%A8%E6%A8%A1%E5%BC%8F"><span class="toc-number">4.4.2.</span> <span class="toc-text">适配器模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%B0%83%E7%94%A8%E9%93%BE%E7%9A%84%E6%89%A7%E8%A1%8C"><span class="toc-number">4.4.3.</span> <span class="toc-text">调用链的执行</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%A8%A1%E6%8B%9F%E5%AE%9E%E7%8E%B0%E8%B0%83%E7%94%A8%E9%93%BE"><span class="toc-number">4.4.4.</span> <span class="toc-text">模拟实现调用链</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8A%A8%E6%80%81%E9%80%9A%E7%9F%A5%E8%B0%83%E7%94%A8"><span class="toc-number">4.4.5.</span> <span class="toc-text">动态通知调用</span></a></li></ol></li></ol></li></ol></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">&copy;2020 - 2023 By 狼族少年、血狼</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><button id="go-up" type="button" title="回到顶部"><span class="scroll-percent"></span><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.umd.min.js"></script><div class="js-pjax"></div><script defer="defer" id="ribbon" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/dist/canvas-ribbon.min.js" size="150" alpha="0.6" zIndex="-1" mobile="false" data-click="false"></script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="is-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span>  数据库加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><hr/><div id="local-search-results"></div></div></div><div id="search-mask"></div><script src="/js/search/local-search.js"></script></div></body></html>